From 91bcaaccfd68f19b0978336083d1409bedd13a4a Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Mon, 14 Dec 2015 15:47:44 +0000 Subject: Update to duktape snapshot suggested by svaarala. http://duktape.org/snapshots/duktape-1.3.99-20151209151055-v1.3.0-383-gb7b1c5f-duk-config-improvements.tar.xz --- javascript/duktape/duk_config.h | 4112 +++++++++++++++++++---------------- javascript/duktape/duktape.c | 4532 +++++++++++++++++++++++++-------------- javascript/duktape/duktape.h | 40 +- 3 files changed, 5177 insertions(+), 3507 deletions(-) (limited to 'javascript') diff --git a/javascript/duktape/duk_config.h b/javascript/duktape/duk_config.h index adf275432..f6ee91cdd 100644 --- a/javascript/duktape/duk_config.h +++ b/javascript/duktape/duk_config.h @@ -1,163 +1,105 @@ /* - * Determine platform features, select feature selection defines - * (e.g. _XOPEN_SOURCE), include system headers, and define DUK_USE_xxx - * defines which are (only) checked in Duktape internal code for - * activated features. Duktape feature selection is based on automatic - * feature detection, user supplied DUK_OPT_xxx defines, and optionally - * a "duk_custom.h" user header (if DUK_OPT_HAVE_CUSTOM_H is defined). + * duk_config.h configuration header generated by genconfig.py. * - * When compiling Duktape, DUK_COMPILING_DUKTAPE is set, and this file - * is included before any system headers are included. Feature selection - * defines (e.g. _XOPEN_SOURCE) are defined here before any system headers - * are included (which is a requirement for system headers to work correctly). - * This file is responsible for including all system headers and contains - * all platform dependent cruft in general. When compiling user code, - * DUK_COMPILING_DUKTAPE is not defined, and we must avoid e.g. defining - * unnecessary feature selection defines. + * Git commit: b7b1c5fd2d1d4550140d57e05a7b32f540082bfa + * Git describe: v1.3.0-383-gb7b1c5f + * Git branch: duk-config-improvements * - * The general order of handling: - * - Compiler feature detection (require no includes) - * - Intermediate platform detection (-> easier platform defines) - * - Platform detection, system includes, byte order detection, etc - * - ANSI C wrappers (e.g. DUK_MEMCMP), wrappers for constants, etc - * - DUK_USE_xxx defines are resolved based on input defines - * - Duktape Date provider settings - * - Final sanity checks + * Supported platforms: + * - Mac OSX, iPhone, Darwin + * - OpenBSD + * - Generic BSD + * - Atari ST TOS + * - AmigaOS + * - Windows + * - Flashplayer (Crossbridge) + * - QNX + * - TI-Nspire + * - Emscripten + * - Linux + * - Solaris + * - Generic POSIX + * - Cygwin + * - Generic UNIX + * - Generic fallback * - * DUK_F_xxx are internal feature detection macros which should not be - * used outside this header. + * Supported architectures: + * - x86 + * - x64 + * - x32 + * - ARM 32-bit + * - ARM 64-bit + * - MIPS 32-bit + * - MIPS 64-bit + * - PowerPC 32-bit + * - PowerPC 64-bit + * - SPARC 32-bit + * - SPARC 64-bit + * - SuperH + * - Motorola 68k + * - Emscripten + * - Generic * - * Useful resources: + * Supported compilers: + * - Clang + * - GCC + * - MSVC + * - Emscripten + * - TinyC + * - VBCC + * - Bruce's C compiler + * - Generic * - * http://sourceforge.net/p/predef/wiki/Home/ - * http://sourceforge.net/p/predef/wiki/Architectures/ - * http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor - * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types - * - * Preprocessor defines available in a particular GCC: - * - * gcc -dM -E - = 199901L) -#define DUK_F_C99 -#endif - -#undef DUK_F_CPP -#if defined(__cplusplus) -#define DUK_F_CPP -#endif - -#undef DUK_F_CPP11 -#if defined(__cplusplus) && (__cplusplus >= 201103L) -#define DUK_F_CPP11 -#endif - -/* - * Provides the duk_rdtsc() inline function (if available), limited to - * GCC C99. - * - * See: http://www.mcs.anl.gov/~kazutomo/rdtsc.html + * Intermediate helper defines */ -/* XXX: more accurate detection of what gcc versions work; more inline - * asm versions for other compilers. - */ -#if defined(__GNUC__) && defined(__i386__) && defined(DUK_F_C99) && \ - !defined(__cplusplus) /* unsigned long long not standard */ -static __inline__ unsigned long long duk_rdtsc(void) { - unsigned long long int x; - __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); - return x; -} -#define DUK_USE_RDTSC() duk_rdtsc() -#elif defined(__GNUC__) && defined(__x86_64__) && defined(DUK_F_C99) && \ - !defined(__cplusplus) /* unsigned long long not standard */ -static __inline__ unsigned long long duk_rdtsc(void) { - unsigned hi, lo; - __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); - return ((unsigned long long) lo) | (((unsigned long long) hi) << 32); -} -#define DUK_USE_RDTSC() duk_rdtsc() +/* 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 available */ -#undef DUK_USE_RDTSC +/* not configured for DLL build */ +#undef DUK_F_DLL_BUILD #endif -/* - * Intermediate platform, architecture, and compiler detection. These are - * hopelessly intertwined - e.g. architecture defines depend on compiler etc. - * - * Provide easier defines for platforms and compilers which are often tricky - * or verbose to detect. The intent is not to provide intermediate defines for - * all features; only if existing feature defines are inconvenient. - */ - -/* Intel x86 (32-bit) */ -#if defined(i386) || defined(__i386) || defined(__i386__) || \ - defined(__i486__) || defined(__i586__) || defined(__i686__) || \ - defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ - defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) -#define DUK_F_X86 +/* Apple OSX, iOS */ +#if defined(__APPLE__) +#define DUK_F_APPLE #endif -/* AMD64 (64-bit) */ -#if defined(__amd64__) || defined(__amd64) || \ - defined(__x86_64__) || defined(__x86_64) || \ - defined(_M_X64) || defined(_M_AMD64) -#define DUK_F_X64 +/* OpenBSD */ +#if defined(__OpenBSD__) || defined(__OpenBSD) +#define DUK_F_OPENBSD #endif -/* X32: 64-bit with 32-bit pointers (allows packed tvals). X32 support is - * not very mature yet. - * - * https://sites.google.com/site/x32abi/ - */ -#if defined(DUK_F_X64) && \ - (defined(_ILP32) || defined(__ILP32__)) -#define DUK_F_X32 -/* define only one of: DUK_F_X86, DUK_F_X32, or DUK_F_X64 */ -#undef DUK_F_X64 -#undef DUK_F_X86 +/* NetBSD */ +#if defined(__NetBSD__) || defined(__NetBSD) +#define DUK_F_NETBSD #endif -/* ARM */ -#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) -#define DUK_F_ARM +/* FreeBSD */ +#if defined(__FreeBSD__) || defined(__FreeBSD) +#define DUK_F_FREEBSD #endif -/* MIPS */ -/* Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ -#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ - defined(_R3000) || defined(_R4000) || defined(_R5900) || \ - defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ - defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ - defined(__mips) || defined(__MIPS__) -#define DUK_F_MIPS -#if defined(__LP64__) || defined(__mips64) || defined(__mips64__) || \ - defined(__mips_n64) -#define DUK_F_MIPS64 -#else -#define DUK_F_MIPS32 -#endif +/* BSD variant */ +#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ + defined(__bsdi__) || defined(__DragonFly__) +#define DUK_F_BSD #endif -/* SuperH */ -#if defined(__sh__) || \ - defined(__sh1__) || defined(__SH1__) || \ - defined(__sh2__) || defined(__SH2__) || \ - defined(__sh3__) || defined(__SH3__) || \ - defined(__sh4__) || defined(__SH4__) || \ - defined(__sh5__) || defined(__SH5__) -#define DUK_F_SUPERH +/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC + * apparently, so to use with VBCC user must define __TOS__ manually. + */ +#if defined(__TOS__) +#define DUK_F_TOS #endif /* Motorola 68K. Not defined by VBCC, so user must define one of these @@ -167,40 +109,77 @@ static __inline__ unsigned long long duk_rdtsc(void) { #define DUK_F_M68K #endif +/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must + * define 'AMIGA' manually when using VBCC. + */ +#if defined(AMIGA) || defined(__amigaos__) +#define DUK_F_AMIGAOS +#endif + /* PowerPC */ #if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) #define DUK_F_PPC -#if defined(__PPC64__) +#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64) #define DUK_F_PPC64 #else #define DUK_F_PPC32 #endif #endif +/* Windows, both 32-bit and 64-bit */ +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ + defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +#define DUK_F_WINDOWS +#if defined(_WIN64) || defined(WIN64) +#define DUK_F_WIN64 +#else +#define DUK_F_WIN32 +#endif +#endif + +/* Flash player (e.g. Crossbridge) */ +#if defined(__FLASHPLAYER__) +#define DUK_F_FLASHPLAYER +#endif + +/* QNX */ +#if defined(__QNX__) +#define DUK_F_QNX +#endif + +/* TI-Nspire (using Ndless) */ +#if defined(_TINSPIRE) +#define DUK_F_TINSPIRE +#endif + +/* Emscripten (provided explicitly by user), improve if possible */ +#if defined(EMSCRIPTEN) +#define DUK_F_EMSCRIPTEN +#endif + +/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ +#if defined(__BCC__) || defined(__BCC_VERSION__) +#define DUK_F_BCC +#endif + /* Linux */ #if defined(__linux) || defined(__linux__) || defined(linux) #define DUK_F_LINUX #endif -/* FreeBSD */ -#if defined(__FreeBSD__) || defined(__FreeBSD) -#define DUK_F_FREEBSD -#endif - -/* NetBSD */ -#if defined(__NetBSD__) || defined(__NetBSD) -#define DUK_F_NETBSD +/* illumos / Solaris */ +#if defined(__sun) && defined(__SVR4) +#define DUK_F_SUN #endif -/* OpenBSD */ -#if defined(__OpenBSD__) || defined(__OpenBSD) -#define DUK_F_OPENBSD +/* POSIX */ +#if defined(__posix) +#define DUK_F_POSIX #endif -/* BSD variant */ -#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ - defined(__bsdi__) || defined(__DragonFly__) -#define DUK_F_BSD +/* Cygwin */ +#if defined(__CYGWIN__) +#define DUK_F_CYGWIN #endif /* Generic Unix (includes Cygwin) */ @@ -209,58 +188,111 @@ static __inline__ unsigned long long duk_rdtsc(void) { #define DUK_F_UNIX #endif -/* Cygwin */ -#if defined(__CYGWIN__) -#define DUK_F_CYGWIN +/* 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 -/* Windows (32-bit or above) */ -#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ - defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) -#define DUK_F_WINDOWS +/* 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/ + */ +#if defined(__amd64__) || defined(__amd64) || \ + defined(__x86_64__) || defined(__x86_64) || \ + defined(_M_X64) || defined(_M_AMD64) +#if defined(__ILP32__) || defined(_ILP32) +#define DUK_F_X32 +#else +#define DUK_F_X64 +#endif +#elif defined(i386) || defined(__i386) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__) || \ + defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ + defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) +#if defined(__LP64__) || defined(_LP64) +/* This should not really happen, but would indicate x64. */ +#define DUK_F_X64 +#else +#define DUK_F_X86 +#endif #endif -#if defined(__APPLE__) -#define DUK_F_APPLE +/* ARM */ +#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) +#define DUK_F_ARM +#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) +#define DUK_F_ARM64 +#else +#define DUK_F_ARM32 +#endif #endif -/* Atari ST TOS. __TOS__ defined by PureC (which doesn't work as a target now - * because int is 16-bit, to be fixed). No platform define in VBCC apparently, - * so to use with VBCC, user must define '__TOS__' manually. - */ -#if defined(__TOS__) -#define DUK_F_TOS +/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ +#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ + defined(_R3000) || defined(_R4000) || defined(_R5900) || \ + defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ + defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ + defined(__mips) || defined(__MIPS__) +#define DUK_F_MIPS +#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \ + defined(__mips64__) || defined(__mips_n64) +#define DUK_F_MIPS64 +#else +#define DUK_F_MIPS32 +#endif #endif -/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must - * define 'AMIGA' manually. - */ -#if defined(AMIGA) || defined(__amigaos__) -#define DUK_F_AMIGAOS +/* SPARC */ +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#define DUK_F_SPARC +#if defined(__LP64__) || defined(_LP64) +#define DUK_F_SPARC64 +#else +#define DUK_F_SPARC32 +#endif #endif -/* Flash player (e.g. Crossbridge) */ -#if defined(__FLASHPLAYER__) -#define DUK_F_FLASHPLAYER +/* SuperH */ +#if defined(__sh__) || \ + defined(__sh1__) || defined(__SH1__) || \ + defined(__sh2__) || defined(__SH2__) || \ + defined(__sh3__) || defined(__SH3__) || \ + defined(__sh4__) || defined(__SH4__) || \ + defined(__sh5__) || defined(__SH5__) +#define DUK_F_SUPERH #endif -/* Emscripten (provided explicitly by user), improve if possible */ -#if defined(EMSCRIPTEN) -#define DUK_F_EMSCRIPTEN +/* Clang */ +#if defined(__clang__) +#define DUK_F_CLANG #endif -/* QNX */ -#if defined(__QNX__) -#define DUK_F_QNX +/* C++ */ +#undef DUK_F_CPP +#if defined(__cplusplus) +#define DUK_F_CPP #endif -/* TI-Nspire (using Ndless) */ -#if defined(_TINSPIRE) -#define DUK_F_TINSPIRE +/* C99 or above */ +#undef DUK_F_C99 +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define DUK_F_C99 +#endif + +/* C++11 or above */ +#undef DUK_F_CPP11 +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define DUK_F_CPP11 #endif -/* GCC and GCC version convenience define. */ -#if defined(__GNUC__) +/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */ +#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG) #define DUK_F_GCC #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) /* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */ @@ -270,16 +302,9 @@ static __inline__ unsigned long long duk_rdtsc(void) { #endif #endif -/* Clang */ -#if defined(__clang__) -#define DUK_F_CLANG -/* It seems clang also defines __GNUC__, so undo the GCC detection. */ -#if defined(DUK_F_GCC) -#undef DUK_F_GCC -#endif -#if defined(DUK_F_GCC_VERSION) -#undef DUK_F_GCC_VERSION -#endif +/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */ +#if defined(__MINGW32__) || defined(__MINGW64__) +#define DUK_F_MINGW #endif /* MSVC */ @@ -298,129 +323,65 @@ static __inline__ unsigned long long duk_rdtsc(void) { #endif #endif /* _MSC_VER */ -/* MinGW */ -#if defined(__MINGW32__) || defined(__MINGW64__) -/* NOTE: Also GCC flags are detected (DUK_F_GCC etc). */ -#define DUK_F_MINGW -#endif - -/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ -#if defined(__BCC__) || defined(__BCC_VERSION__) -#define DUK_F_BCC +/* TinyC */ +#if defined(__TINYC__) +/* http://bellard.org/tcc/tcc-doc.html#SEC9 */ +#define DUK_F_TINYC #endif +/* VBCC */ #if defined(__VBCC__) #define DUK_F_VBCC #endif +/* uclibc */ +#if defined(__UCLIBC__) +#define DUK_F_UCLIBC +#endif + /* - * Platform detection, system includes, Date provider selection. - * - * Feature selection (e.g. _XOPEN_SOURCE) must happen before any system - * headers are included. This header should avoid providing any feature - * selection defines when compiling user code (only when compiling Duktape - * itself). If a feature selection option is required for user code to - * compile correctly (e.g. it is needed for type detection), it should - * probably be -checked- here, not defined here. - * - * Date provider selection seems a bit out-of-place here, but since - * the date headers and provider functions are heavily platform - * specific, there's little point in duplicating the platform if-else - * ladder. All platform specific Date provider functions are in - * duk_bi_date.c; here we provide appropriate #defines to enable them, - * and include all the necessary system headers so that duk_bi_date.c - * compiles. Date "providers" are: - * - * NOW = getting current time (required) - * TZO = getting local time offset (required) - * PRS = parse datetime (optional) - * FMT = format datetime (optional) - * - * There's a lot of duplication here, unfortunately, because many - * platforms have similar (but not identical) headers, Date providers, - * etc. The duplication could be removed by more complicated nested - * #ifdefs, but it would then be more difficult to make fixes which - * affect only a specific platform. - * - * XXX: add a way to provide custom functions to provide the critical - * primitives; this would be convenient when porting to unknown platforms - * (rather than muck with Duktape internals). + * Platform autodetection */ -#if defined(DUK_COMPILING_DUKTAPE) && \ - (defined(DUK_F_LINUX) || defined(DUK_F_EMSCRIPTEN)) -/* A more recent Emscripten (2014-05) seems to lack "linux" environment - * defines, so check for Emscripten explicitly. +/* Workaround for older C++ compilers before including , + * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 */ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif -#ifndef _GNU_SOURCE -#define _GNU_SOURCE /* e.g. getdate_r */ -#endif -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE /* e.g. strptime */ +#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) +#define __STDC_LIMIT_MACROS #endif +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) +#define __STDC_CONSTANT_MACROS #endif -#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) -/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L -#endif - -#undef DUK_F_MSVC_CRT_SECURE -#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) -/* http://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx - * http://msdn.microsoft.com/en-us/library/wd3wzwts.aspx - * Seem to be available since VS2005. - */ -#if (_MSC_VER >= 1400) -/* VS2005+, secure CRT functions are preferred. Windows Store applications - * (and probably others) should use these. - */ -#define DUK_F_MSVC_CRT_SECURE -#endif -#if (_MSC_VER < 1700) -/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ -#define DUK_F_NO_STDINT_H -#endif -/* Initial fix: disable secure CRT related warnings when compiling Duktape - * itself (must be defined before including Windows headers). Don't define - * for user code including duktape.h. - */ -#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif -#endif /* DUK_F_WINDOWS && _MSC_VER */ - -#if defined(DUK_F_TOS) || defined(DUK_F_BCC) -#define DUK_F_NO_STDINT_H -#endif - -/* Workaround for older C++ compilers before including , - * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 - */ -#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) -#define __STDC_LIMIT_MACROS -#endif -#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) -#define __STDC_CONSTANT_MACROS -#endif - -#if defined(__APPLE__) -/* Mac OSX, iPhone, Darwin */ +#if defined(DUK_F_APPLE) +/* --- Mac OSX, iPhone, Darwin --- */ #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 #include #include #include + +/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ +#if TARGET_IPHONE_SIMULATOR +#define DUK_USE_OS_STRING "iphone-sim" +#elif TARGET_OS_IPHONE +#define DUK_USE_OS_STRING "iphone" +#elif TARGET_OS_MAC +#define DUK_USE_OS_STRING "ios" +#else +#define DUK_USE_OS_STRING "ios-unknown" +#endif + +/* Use _setjmp() on Apple by default, see GH-55. */ +#define DUK_USE_UNDERSCORE_SETJMP +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) #elif defined(DUK_F_OPENBSD) +/* --- OpenBSD --- */ /* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ #define DUK_USE_DATE_NOW_GETTIMEOFDAY #define DUK_USE_DATE_TZO_GMTIME_R @@ -428,45 +389,52 @@ static __inline__ unsigned long long duk_rdtsc(void) { #define DUK_USE_DATE_FMT_STRFTIME #include #include -#include #include #include #include + +#define DUK_USE_OS_STRING "openbsd" #elif defined(DUK_F_BSD) -/* other BSD */ +/* --- Generic BSD --- */ #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 #include #include #include + +#define DUK_USE_OS_STRING "bsd" #elif defined(DUK_F_TOS) -/* Atari ST TOS */ +/* --- Atari ST TOS --- */ #define DUK_USE_DATE_NOW_TIME #define DUK_USE_DATE_TZO_GMTIME /* no parsing (not an error) */ #define DUK_USE_DATE_FMT_STRFTIME -#include #include + +#define DUK_USE_OS_STRING "tos" + +/* TOS on M68K is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K) +#define DUK_USE_BYTEORDER 3 +#endif #elif defined(DUK_F_AMIGAOS) +/* --- AmigaOS --- */ #if defined(DUK_F_M68K) /* AmigaOS on M68k */ #define DUK_USE_DATE_NOW_TIME #define DUK_USE_DATE_TZO_GMTIME /* no parsing (not an error) */ #define DUK_USE_DATE_FMT_STRFTIME -#include #include #elif defined(DUK_F_PPC) #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 #ifndef UINTPTR_MAX #define UINTPTR_MAX UINT_MAX @@ -474,7 +442,23 @@ static __inline__ unsigned long long duk_rdtsc(void) { #else #error AmigaOS but not M68K/PPC, not supported now #endif + +#define DUK_USE_OS_STRING "amigaos" + +/* AmigaOS on M68K or PPC is always big endian. */ +#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) +#define DUK_USE_BYTEORDER 3 +#endif #elif defined(DUK_F_WINDOWS) +/* --- Windows --- */ +/* Initial fix: disable secure CRT related warnings when compiling Duktape + * itself (must be defined before including Windows headers). Don't define + * for user code including duktape.h. + */ +#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + /* Windows 32-bit and 64-bit are currently the same. */ /* MSVC does not have sys/param.h */ #define DUK_USE_DATE_NOW_WINDOWS @@ -484,180 +468,850 @@ static __inline__ unsigned long long duk_rdtsc(void) { * the ISO 8601 standard format. */ #if defined(DUK_COMPILING_DUKTAPE) +/* Only include when compiling Duktape to avoid polluting application build + * with a lot of unnecessary defines. + */ #include #endif -#include + +#define DUK_USE_OS_STRING "windows" + +/* On Windows, assume we're little endian. Even Itanium which has a + * configurable endianness runs little endian in Windows. + */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif #elif defined(DUK_F_FLASHPLAYER) -/* Crossbridge */ +/* --- Flashplayer (Crossbridge) --- */ #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 #include #include + +#define DUK_USE_OS_STRING "flashplayer" + +#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER) +#define DUK_USE_BYTEORDER 1 +#endif #elif defined(DUK_F_QNX) +/* --- QNX --- */ +#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) +/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L +#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 #include #include + +#define DUK_USE_OS_STRING "qnx" #elif defined(DUK_F_TINSPIRE) +/* --- TI-Nspire --- */ #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 #include #include -#elif defined(DUK_F_LINUX) + +#define DUK_USE_OS_STRING "tinspire" +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + +#include +#if defined(DUK_F_BCC) +/* no endian.h */ +#else +#include +#endif /* DUK_F_BCC */ +#include +#include +#include +#include + #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 + +#define DUK_USE_OS_STRING "emscripten" +#elif defined(DUK_F_LINUX) +/* --- Linux --- */ +#if defined(DUK_COMPILING_DUKTAPE) +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* e.g. getdate_r */ +#endif +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE /* e.g. strptime */ +#endif +#endif /* DUK_COMPILING_DUKTAPE */ + #include #if defined(DUK_F_BCC) -/* no endian.h */ +/* no endian.h or stdint.h */ #else #include +#include #endif /* DUK_F_BCC */ -#include #include #include #include -#elif defined(__posix) -/* POSIX */ + +#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 + +#define DUK_USE_OS_STRING "linux" +#elif defined(DUK_F_SUN) +/* --- Solaris --- */ #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 +#include #include #include #include -#elif defined(DUK_F_CYGWIN) -/* Cygwin -- don't use strptime() for now */ + +#define DUK_USE_OS_STRING "solaris" +#elif defined(DUK_F_POSIX) +/* --- Generic POSIX --- */ #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 #include #include #include -#else -/* Other UNIX, hopefully others */ + +#define DUK_USE_OS_STRING "posix" +#elif defined(DUK_F_CYGWIN) +/* --- Cygwin --- */ +/* don't use strptime() for now */ #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 -#if defined(DUK_F_BCC) -/* no endian.h */ -#else #include -#endif /* DUK_F_BCC */ -#include #include #include #include -#endif -/* Shared includes */ +#define DUK_USE_UNDERSCORE_SETJMP +#define DUK_SETJMP(jb) _setjmp((jb)) +#define DUK_LONGJMP(jb) _longjmp((jb), 1) + +#define DUK_USE_OS_STRING "windows" +#elif defined(DUK_F_UNIX) +/* --- Generic UNIX --- */ +#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 +#define DUK_USE_OS_STRING "unknown" +#else +/* --- Generic fallback --- */ +/* The most portable current time provider is time(), but it only has a + * one second resolution. + */ +#define DUK_USE_DATE_NOW_TIME + +/* The most portable way to figure out local time offset is gmtime(), + * but it's not thread safe so use with caution. + */ +#define DUK_USE_DATE_TZO_GMTIME + +/* Avoid custom date parsing and formatting for portability. */ +#undef DUK_USE_DATE_PRS_STRPTIME +#undef DUK_USE_DATE_FMT_STRFTIME + +/* Rely on C89 headers only; time.h must be here. */ +#include + +#define DUK_USE_OS_STRING "unknown" +#endif /* autodetect platform */ + +/* Shared includes: C89 */ #include #include #include #include /* varargs */ #include #include /* e.g. ptrdiff_t */ +#include +#include + +/* date.h is omitted, and included per platform */ + +/* Shared includes: stdint.h is C99 */ #if defined(DUK_F_NO_STDINT_H) /* stdint.h not available */ #else -/* Technically C99 (C++11) but found in many systems. Note the workaround - * above for some C++ compilers (__STDC_LIMIT_MACROS etc). +/* Technically C99 (C++11) but found in many systems. On some systems + * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before + * including stdint.h (see above). */ #include #endif -#include - -#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ - !defined(DUK_F_BCC) -/* ULL / LL preprocessor constants should be avoided because they're not - * always available. With suitable options, some compilers will support - * 64-bit integer types but won't support ULL / LL preprocessor constants. - * Assume C99/C++11 environments have these. However, BCC is nominally - * C99 but doesn't support these constants. - */ -#define DUK_F_ULL_CONSTS -#endif /* - * Detection for specific libc variants (like uclibc) and other libc specific - * features. Potentially depends on the #includes above. + * Architecture autodetection */ -#if defined(__UCLIBC__) -#define DUK_F_UCLIBC +#if defined(DUK_F_X86) +/* --- x86 --- */ +#define DUK_USE_ARCH_STRING "x86" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 #endif - -/* - * Wrapper typedefs and constants for integer types, also sanity check types. - * - * C99 typedefs are quite good but not always available, and we want to avoid - * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for - * all C99 typedefs and Duktape code should only use these typedefs. Type - * detection when C99 is not supported is best effort and may end up detecting - * some types incorrectly. - * - * Pointer sizes are a portability problem: pointers to different types may - * have a different size and function pointers are very difficult to manage - * portably. - * - * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types - * - * Note: there's an interesting corner case when trying to define minimum - * signed integer value constants which leads to the current workaround of - * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt - * for a longer discussion. - * - * Note: avoid typecasts and computations in macro integer constants as they - * can then no longer be used in macro relational expressions (such as - * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on - * being able to compare DUK_SIZE_MAX against a limit. +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. */ - -/* XXX: add feature options to force basic types from outside? */ - -#if !defined(INT_MAX) -#error INT_MAX not defined +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 #endif - -/* Check that architecture is two's complement, standard C allows e.g. - * INT_MIN to be -2**31+1 (instead of -2**31). +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X64) +/* --- x64 --- */ +#define DUK_USE_ARCH_STRING "x64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. */ -#if defined(INT_MAX) && defined(INT_MIN) -#if INT_MAX != -(INT_MIN + 1) -#error platform does not seem complement of two +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 #endif -#else -#error cannot check complement of two +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_X32) +/* --- x32 --- */ +#define DUK_USE_ARCH_STRING "x32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 #endif - -/* Pointer size determination based on architecture. - * XXX: unsure about BCC correctness. +/* XXX: This is technically not guaranteed because it's possible to configure + * an x86 to require aligned accesses with Alignment Check (AC) flag. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 1 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM32) +/* --- ARM 32-bit --- */ +#define DUK_USE_ARCH_STRING "arm32" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_ARM64) +/* --- ARM 64-bit --- */ +#define DUK_USE_ARCH_STRING "arm64" +/* Byte order varies, so rely on autodetect. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS32) +/* --- MIPS 32-bit --- */ +#define DUK_USE_ARCH_STRING "mips32" +/* MIPS byte order varies so rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux MIPS except for doubles, which need align by 4. Alignment + * requirements vary based on target though. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_MIPS64) +/* --- MIPS 64-bit --- */ +#define DUK_USE_ARCH_STRING "mips64" +/* MIPS byte order varies so rely on autodetection. */ +/* Good default is a bit arbitrary because alignment requirements + * depend on target. See https://github.com/svaarala/duktape/issues/102. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC32) +/* --- PowerPC 32-bit --- */ +#define DUK_USE_ARCH_STRING "ppc32" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_PPC64) +/* --- PowerPC 64-bit --- */ +#define DUK_USE_ARCH_STRING "ppc64" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC32) +/* --- SPARC 32-bit --- */ +#define DUK_USE_ARCH_STRING "sparc32" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SPARC64) +/* --- SPARC 64-bit --- */ +#define DUK_USE_ARCH_STRING "sparc64" +/* SPARC byte order varies so rely on autodetection. */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_SUPERH) +/* --- SuperH --- */ +#define DUK_USE_ARCH_STRING "sh" +/* Byte order varies, rely on autodetection. */ +/* Based on 'make checkalign' there are no alignment requirements on + * Linux SH4, but align by 4 is probably a good basic default. + */ +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 4 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_M68K) +/* --- Motorola 68k --- */ +#define DUK_USE_ARCH_STRING "m68k" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 3 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#define DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_USE_ARCH_STRING "emscripten" +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#if !defined(DUK_USE_ALIGN_BY) +#define DUK_USE_ALIGN_BY 8 +#endif +#undef DUK_USE_PACKED_TVAL +#define DUK_F_PACKED_TVAL_PROVIDED +#else +/* --- Generic --- */ +/* These are necessary wild guesses. */ +#define DUK_USE_ARCH_STRING "generic" +/* Rely on autodetection for byte order, alignment, and packed tval. */ +#endif /* autodetect architecture */ + +/* + * Compiler autodetection + */ + +#if defined(DUK_F_CLANG) +/* --- Clang --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* Clang: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#else +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "clang" +#else +#define DUK_USE_COMPILER_STRING "clang" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#define DUK_F_VARIADIC_MACROS_PROVIDED +#elif defined(DUK_F_GCC) +/* --- GCC --- */ +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +/* C99 / C++11 and above: rely on va_copy() which is required. */ +#define DUK_VA_COPY(dest,src) va_copy(dest,src) +#else +/* GCC: assume we have __va_copy() in non-C99 mode. */ +#define DUK_VA_COPY(dest,src) __va_copy(dest,src) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L) +/* since gcc-2.5 */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* since gcc-4.5 */ +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif + +#define DUK_USE_BRANCH_HINTS +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) +/* GCC: test not very accurate; enable only in relatively recent builds + * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) + */ +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) +#endif + +#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ + defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static +#endif + +#if defined(DUK_F_MINGW) +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "mingw++" +#else +#define DUK_USE_COMPILER_STRING "mingw" +#endif +#else +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "g++" +#else +#define DUK_USE_COMPILER_STRING "gcc" +#endif +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600) +#define DUK_USE_GCC_PRAGMAS +#else +#undef DUK_USE_GCC_PRAGMAS +#endif + +#define DUK_USE_PACK_GCC_ATTR +#define DUK_F_VARIADIC_MACROS_PROVIDED +#elif defined(DUK_F_MSVC) +/* --- MSVC --- */ +/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ +#define DUK_NORETURN(decl) __declspec(noreturn) decl + +/* XXX: DUK_UNREACHABLE for msvc? */ + +#undef DUK_USE_BRANCH_HINTS + +/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */ +/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */ + +#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) +/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're + * compiling Duktape or the application. + */ +#if defined(DUK_COMPILING_DUKTAPE) +#define DUK_EXTERNAL_DECL extern __declspec(dllexport) +#define DUK_EXTERNAL __declspec(dllexport) +#else +#define DUK_EXTERNAL_DECL extern __declspec(dllimport) +#define DUK_EXTERNAL should_not_happen +#endif +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL extern +#define DUK_INTERNAL /*empty*/ +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#endif + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "msvc++" +#else +#define DUK_USE_COMPILER_STRING "msvc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) +#define DUK_USE_VARIADIC_MACROS +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +/* VS2005+ should have variadic macros even when they're not C99. */ +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS + +#define DUK_USE_PACK_MSVC_PRAGMA + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#define DUK_SNPRINTF snprintf +#define DUK_VSNPRINTF vsnprintf +#else +/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does + * NOT NUL terminate on truncation, but Duktape code never assumes that. + * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 + */ +#define DUK_SNPRINTF _snprintf +#define DUK_VSNPRINTF _vsnprintf +#endif +#define DUK_F_VARIADIC_MACROS_PROVIDED +#elif defined(DUK_F_EMSCRIPTEN) +/* --- Emscripten --- */ +#define DUK_NORETURN(decl) decl __attribute__((noreturn)) + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_unreachable) +#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) +#endif +#endif + +#define DUK_USE_BRANCH_HINTS +#define DUK_LIKELY(x) __builtin_expect((x), 1) +#define DUK_UNLIKELY(x) __builtin_expect((x), 0) + +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_NOINLINE __attribute__((noinline)) +#define DUK_INLINE inline +#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) +#endif + +#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern +#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if defined(DUK_SINGLE_FILE) +#define DUK_INTERNAL_DECL static +#define DUK_INTERNAL static +#else +#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern +#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#endif +#define DUK_LOCAL_DECL static +#define DUK_LOCAL static + +#define DUK_USE_COMPILER_STRING "emscripten" + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#undef DUK_USE_FLEX_C99 +#undef DUK_USE_FLEX_ZEROSIZE +#undef DUK_USE_FLEX_ONESIZE +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 +#else +#define DUK_USE_FLEX_ZEROSIZE +#endif + +#undef DUK_USE_GCC_PRAGMAS +#define DUK_USE_PACK_CLANG_ATTR +#define DUK_F_VARIADIC_MACROS_PROVIDED +#elif defined(DUK_F_TINYC) +/* --- TinyC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "tinyc++" +#else +#define DUK_USE_COMPILER_STRING "tinyc" +#endif + +/* http://bellard.org/tcc/tcc-doc.html#SEC7 */ +#define DUK_USE_VARIADIC_MACROS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#define DUK_F_VARIADIC_MACROS_PROVIDED +#elif defined(DUK_F_VBCC) +/* --- VBCC --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "vbcc-c++" +#else +#define DUK_USE_COMPILER_STRING "vbcc" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +#define DUK_USE_FLEX_ZEROSIZE +#define DUK_USE_PACK_DUMMY_MEMBER +#define DUK_F_VARIADIC_MACROS_PROVIDED +#elif defined(DUK_F_BCC) +/* --- Bruce's C compiler --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "bcc++" +#else +#define DUK_USE_COMPILER_STRING "bcc" +#endif + +/* XXX */ +#undef DUK_USE_VARIADIC_MACROS + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER + +/* BCC, assume we're on x86. */ +#if !defined(DUK_USE_BYTEORDER) +#define DUK_USE_BYTEORDER 1 +#endif +#define DUK_F_VARIADIC_MACROS_PROVIDED +#else +/* --- Generic --- */ +#undef DUK_USE_BRANCH_HINTS + +#if defined(DUK_F_CPP) +#define DUK_USE_COMPILER_STRING "generic-c++" +#else +#define DUK_USE_COMPILER_STRING "generic" +#endif + +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif + +/* Most portable, wastes space */ +#define DUK_USE_FLEX_ONESIZE + +/* Most portable, potentially wastes space */ +#define DUK_USE_PACK_DUMMY_MEMBER +#define DUK_F_VARIADIC_MACROS_PROVIDED +#endif /* autodetect compiler */ + +/* + * Wrapper typedefs and constants for integer types, also sanity check types. + * + * C99 typedefs are quite good but not always available, and we want to avoid + * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for + * all C99 typedefs and Duktape code should only use these typedefs. Type + * detection when C99 is not supported is best effort and may end up detecting + * some types incorrectly. + * + * Pointer sizes are a portability problem: pointers to different types may + * have a different size and function pointers are very difficult to manage + * portably. + * + * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types + * + * Note: there's an interesting corner case when trying to define minimum + * signed integer value constants which leads to the current workaround of + * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt + * for a longer discussion. + * + * Note: avoid typecasts and computations in macro integer constants as they + * can then no longer be used in macro relational expressions (such as + * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on + * being able to compare DUK_SIZE_MAX against a limit. + */ + +/* XXX: add feature options to force basic types from outside? */ + +#if !defined(INT_MAX) +#error INT_MAX not defined +#endif + +/* Check that architecture is two's complement, standard C allows e.g. + * INT_MIN to be -2**31+1 (instead of -2**31). + */ +#if defined(INT_MAX) && defined(INT_MIN) +#if INT_MAX != -(INT_MIN + 1) +#error platform does not seem complement of two +#endif +#else +#error cannot check complement of two +#endif + +/* Pointer size determination based on __WORDSIZE or architecture when + * that's not available. */ #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)) #define DUK_F_32BIT_PTRS @@ -1108,444 +1762,219 @@ typedef duk_uint_t duk_uarridx_t; typedef duk_small_int_t duk_ret_t; #define DUK_RET_MIN DUK_SMALL_INT_MIN #define DUK_RET_MAX DUK_SMALL_INT_MAX - -/* Error codes are represented with platform int. High bits are used - * for flags and such, so 32 bits are needed. - */ -typedef duk_int_t duk_errcode_t; -#define DUK_ERRCODE_MIN DUK_INT_MIN -#define DUK_ERRCODE_MAX DUK_INT_MAX - -/* Codepoint type. Must be 32 bits or more because it is used also for - * internal codepoints. The type is signed because negative codepoints - * are used as internal markers (e.g. to mark EOF or missing argument). - * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to - * ensure duk_uint32_t casts back and forth nicely. Almost everything - * else uses the signed one. - */ -typedef duk_int_t duk_codepoint_t; -typedef duk_uint_t duk_ucodepoint_t; -#define DUK_CODEPOINT_MIN DUK_INT_MIN -#define DUK_CODEPOINT_MAX DUK_INT_MAX -#define DUK_UCODEPOINT_MIN DUK_UINT_MIN -#define DUK_UCODEPOINT_MAX DUK_UINT_MAX - -/* IEEE float/double typedef. */ -typedef float duk_float_t; -typedef double duk_double_t; - -/* We're generally assuming that we're working on a platform with a 32-bit - * address space. If DUK_SIZE_MAX is a typecast value (which is necessary - * if SIZE_MAX is missing), the check must be avoided because the - * preprocessor can't do a comparison. - */ -#if !defined(DUK_SIZE_MAX) -#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX -#elif !defined(DUK_SIZE_MAX_COMPUTED) -#if DUK_SIZE_MAX < 0xffffffffUL -/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value - * which seems incorrect if size_t is (at least) an unsigned 32-bit type. - * However, it doesn't seem useful to error out compilation if this is the - * case. - */ -#endif -#endif - -/* Type for public API calls. */ -typedef struct duk_hthread duk_context; - -/* - * Check whether we should use 64-bit integers - */ - -/* Quite incomplete now. Use 64-bit types if detected (C99 or other detection) - * unless they are known to be unreliable. For instance, 64-bit types are - * available on VBCC but seem to misbehave. - */ -#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC) -#define DUK_USE_64BIT_OPS -#else -#undef DUK_USE_64BIT_OPS -#endif - -/* - * Alignment requirement and support for unaligned accesses - * - * Assume unaligned accesses are not supported unless specifically allowed - * in the target platform. Some platforms may support unaligned accesses - * but alignment to 4 or 8 may still be desirable. - */ - -#undef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#undef DUK_USE_ALIGN_BY - -#if defined(DUK_F_EMSCRIPTEN) -/* Required on at least some targets, so use whenever Emscripten used, - * regardless of compilation target. - */ -#define DUK_USE_ALIGN_BY 8 -#elif defined(DUK_F_ARM) -#define DUK_USE_ALIGN_BY 4 -#elif defined(DUK_F_MIPS32) -/* Based on 'make checkalign' there are no alignment requirements on - * Linux MIPS except for doubles, which need align by 4. Alignment - * requirements vary based on target though. - */ -#define DUK_USE_ALIGN_BY 4 -#elif defined(DUK_F_MIPS64) -/* Good default is a bit arbitrary because alignment requirements - * depend on target. See https://github.com/svaarala/duktape/issues/102. - */ -#define DUK_USE_ALIGN_BY 8 -#elif defined(DUK_F_SUPERH) -/* Based on 'make checkalign' there are no alignment requirements on - * Linux SH4, but align by 4 is probably a good basic default. - */ -#define DUK_USE_ALIGN_BY 4 -#elif defined(DUK_F_X86) || defined(DUK_F_X32) || defined(DUK_F_X64) || \ - defined(DUK_F_BCC) -/* XXX: This is technically not guaranteed because it's possible to configure - * an x86 to require aligned accesses with Alignment Check (AC) flag. - */ -#define DUK_USE_ALIGN_BY 1 -#define DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#else -/* Unknown, use safe default */ -#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 -#undef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#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. - * - * http://stackoverflow.com/questions/11130109/c-struct-size-alignment - * http://stackoverflow.com/questions/10951039/specifying-64-bit-alignment - */ -#if defined(DUK_F_MSVC) -#define DUK_USE_PACK_MSVC_PRAGMA -#elif defined(DUK_F_GCC) -#define DUK_USE_PACK_GCC_ATTR -#elif defined(DUK_F_CLANG) -#define DUK_USE_PACK_CLANG_ATTR -#else -#define DUK_USE_PACK_DUMMY_MEMBER -#endif - -#ifdef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -#define DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS -#else -#undef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS -#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 - * having mostly aligned accesses. - */ -#undef DUK_USE_HOBJECT_LAYOUT_1 -#undef DUK_USE_HOBJECT_LAYOUT_2 -#undef DUK_USE_HOBJECT_LAYOUT_3 -#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) && (DUK_USE_ALIGN_BY == 1) -/* On platforms without any alignment issues, layout 1 is preferable - * because it compiles to slightly less code and provides direct access - * to property keys. - */ -#define DUK_USE_HOBJECT_LAYOUT_1 -#else -/* On other platforms use layout 2, which requires some padding but - * is a bit more natural than layout 3 in ordering the entries. Layout - * 3 is currently not used. + +/* Error codes are represented with platform int. High bits are used + * for flags and such, so 32 bits are needed. */ -#define DUK_USE_HOBJECT_LAYOUT_2 -#endif +typedef duk_int_t duk_errcode_t; +#define DUK_ERRCODE_MIN DUK_INT_MIN +#define DUK_ERRCODE_MAX DUK_INT_MAX -/* - * Byte order and double memory layout detection - * - * Endianness detection is a major portability hassle because the macros - * and headers are not standardized. There's even variance across UNIX - * platforms. Even with "standard" headers, details like underscore count - * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used - * (Crossbridge has a single underscore, for instance). - * - * The checks below are structured with this in mind: several approaches are - * used, and at the end we check if any of them worked. This allows generic - * approaches to be tried first, and platform/compiler specific hacks tried - * last. As a last resort, the user can force a specific endianness, as it's - * not likely that automatic detection will work on the most exotic platforms. - * - * Duktape supports little and big endian machines. There's also support - * for a hybrid used by some ARM machines where integers are little endian - * but IEEE double values use a mixed order (12345678 -> 43218765). This - * byte order for doubles is referred to as "mixed endian". +/* Codepoint type. Must be 32 bits or more because it is used also for + * internal codepoints. The type is signed because negative codepoints + * are used as internal markers (e.g. to mark EOF or missing argument). + * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to + * ensure duk_uint32_t casts back and forth nicely. Almost everything + * else uses the signed one. */ +typedef duk_int_t duk_codepoint_t; +typedef duk_uint_t duk_ucodepoint_t; +#define DUK_CODEPOINT_MIN DUK_INT_MIN +#define DUK_CODEPOINT_MAX DUK_INT_MAX +#define DUK_UCODEPOINT_MIN DUK_UINT_MIN +#define DUK_UCODEPOINT_MAX DUK_UINT_MAX -#undef DUK_F_BYTEORDER -#undef DUK_USE_BYTEORDER_FORCED +/* IEEE float/double typedef. */ +typedef float duk_float_t; +typedef double duk_double_t; -/* DUK_F_BYTEORDER is set as an intermediate value when detection - * succeeds, to one of: - * 1 = little endian - * 2 = mixed (arm hybrid) endian - * 3 = big endian +/* We're generally assuming that we're working on a platform with a 32-bit + * address space. If DUK_SIZE_MAX is a typecast value (which is necessary + * if SIZE_MAX is missing), the check must be avoided because the + * preprocessor can't do a comparison. */ - -/* 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_SIZE_MAX) +#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX +#elif !defined(DUK_SIZE_MAX_COMPUTED) +#if DUK_SIZE_MAX < 0xffffffffUL +/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value + * which seems incorrect if size_t is (at least) an unsigned 32-bit type. + * However, it doesn't seem useful to error out compilation if this is the + * case. */ -#if defined(DUK_OPT_FORCE_BYTEORDER) -#if (DUK_OPT_FORCE_BYTEORDER == 1) -#define DUK_F_BYTEORDER 1 -#elif (DUK_OPT_FORCE_BYTEORDER == 2) -#define DUK_F_BYTEORDER 2 -#elif (DUK_OPT_FORCE_BYTEORDER == 3) -#define DUK_F_BYTEORDER 3 -#else -#error invalid DUK_OPT_FORCE_BYTEORDER value #endif -#define DUK_USE_BYTEORDER_FORCED -#endif /* DUK_OPT_FORCE_BYTEORDER */ +#endif -/* More or less standard endianness predefines provided by header files. - * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER - * will be big endian, see: http://lists.mysql.com/internals/443. - */ -#if !defined(DUK_F_BYTEORDER) -#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ - defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ - defined(__LITTLE_ENDIAN__) -/* Integer little endian */ -#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) -#define DUK_F_BYTEORDER 1 -#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -#define DUK_F_BYTEORDER 2 -#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 1 -#else -/* byte order is little endian but cannot determine IEEE double word order */ -#endif /* float word order */ -#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ - defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ - defined(__BIG_ENDIAN__) -/* Integer big endian */ -#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ - defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -#define DUK_F_BYTEORDER 3 -#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 3 -#else -/* byte order is big endian but cannot determine IEEE double word order */ -#endif /* float word order */ -#else -/* cannot determine byte order */ -#endif /* integer byte order */ -#endif /* !defined(DUK_F_BYTEORDER) */ +/* Type for public API calls. */ +typedef struct duk_hthread duk_context; -/* 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 - * seem to provide __FLOAT_WORD_ORDER__. - * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +/* Check whether we should use 64-bit integers or not. + * + * Quite incomplete now. Use 64-bit types if detected (C99 or other detection) + * unless they are known to be unreliable. For instance, 64-bit types are + * available on VBCC but seem to misbehave. */ -#if !defined(DUK_F_BYTEORDER) && defined(__BYTE_ORDER__) -#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -/* Integer little endian */ -#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ - (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#define DUK_F_BYTEORDER 1 -#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -#define DUK_F_BYTEORDER 2 -#elif !defined(__FLOAT_WORD_ORDER__) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 1 -#else -/* byte order is little endian but cannot determine IEEE double word order */ -#endif /* float word order */ -#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -/* Integer big endian */ -#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ - (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -#define DUK_F_BYTEORDER 3 -#elif !defined(__FLOAT_WORD_ORDER__) -/* Float word order not known, assume not a hybrid. */ -#define DUK_F_BYTEORDER 3 -#else -/* byte order is big endian but cannot determine IEEE double word order */ -#endif /* float word order */ +#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC) +#define DUK_USE_64BIT_OPS #else -/* cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit - * integer ordering and is not relevant +#undef DUK_USE_64BIT_OPS +#endif + +/* + * Fill-ins for platform, architecture, and compiler */ -#endif /* integer byte order */ -#endif /* !defined(DUK_F_BYTEORDER) && defined(__BYTE_ORDER__) */ -/* Atari ST TOS */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_TOS) -#define DUK_F_BYTEORDER 3 +#if !defined(DUK_SETJMP) +#define DUK_USE_SETJMP +#define DUK_SETJMP(jb) setjmp((jb)) +#define DUK_LONGJMP(jb) longjmp((jb), 1) #endif -/* AmigaOS on M68K or PPC */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_AMIGAOS) -#if defined(DUK_F_M68K) || defined(DUK_F_PPC) -#define DUK_F_BYTEORDER 3 +typedef FILE duk_file; +#if !defined(DUK_STDIN) +#define DUK_STDIN stdin #endif +#if !defined(DUK_STDOUT) +#define DUK_STDOUT stdout #endif - -/* On Windows, assume we're little endian. Even Itanium which has a - * configurable endianness runs little endian in Windows. - */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_WINDOWS) -/* XXX: verify that Windows on ARM is little endian for floating point - * values too. - */ -#define DUK_F_BYTEORDER 1 -#endif /* Windows */ - -/* Crossbridge should work with the standard byteorder #ifdefs. It doesn't - * provide _FLOAT_WORD_ORDER but the standard approach now covers that case - * too. This has been left here just in case. - */ -#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_FLASHPLAYER) -#define DUK_F_BYTEORDER 1 +#if !defined(DUK_STDERR) +#define DUK_STDERR stderr #endif -/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: - * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - + * | 0 | 1 | 2 | ..... + * ^-- p=3, points after last valid byte (2) */ -#if defined(DUK_F_BYTEORDER) -#if (DUK_F_BYTEORDER == 1) -#define DUK_USE_INTEGER_LE -#define DUK_USE_DOUBLE_LE -#elif (DUK_F_BYTEORDER == 2) -#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ -#define DUK_USE_DOUBLE_ME -#elif (DUK_F_BYTEORDER == 3) -#define DUK_USE_INTEGER_BE -#define DUK_USE_DOUBLE_BE -#else -#error unsupported: byte order detection failed (internal error, should not happen) -#endif /* byte order */ -#else -#error unsupported: byte order detection failed -#endif /* defined(DUK_F_BYTEORDER) */ - -/* - * Check whether or not a packed duk_tval representation is possible. - * What's basically required is that pointers are 32-bit values - * (sizeof(void *) == 4). Best effort check, not always accurate. - * If guess goes wrong, crashes may result; self tests also verify - * the guess. +#if !defined(DUK_MEMCPY) +#if defined(DUK_F_UCLIBC) +/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide + * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html */ - -#undef DUK_USE_PACKED_TVAL_POSSIBLE - -/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ -#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_F_HAVE_INTTYPES) && defined(DUK_UINTPTR_MAX) -#if (DUK_UINTPTR_MAX <= 0xffffffffUL) -#define DUK_USE_PACKED_TVAL_POSSIBLE +#define DUK_MEMCPY memmove +#else +#define DUK_MEMCPY memcpy #endif #endif - -/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ -#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) -#if (DUK_UINTPTR_MAX <= 0xffffffffUL) -#define DUK_USE_PACKED_TVAL_POSSIBLE +#if !defined(DUK_MEMMOVE) +#define DUK_MEMMOVE memmove #endif +#if !defined(DUK_MEMCMP) +#define DUK_MEMCMP memcmp #endif - -/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ -#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) -#if DUK_SIZE_MAX <= 0xffffffffUL -#define DUK_USE_PACKED_TVAL_POSSIBLE +#if !defined(DUK_MEMSET) +#define DUK_MEMSET memset #endif +#if !defined(DUK_STRLEN) +#define DUK_STRLEN strlen #endif - -/* M68K: packed always possible */ -#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_F_M68K) -#define DUK_USE_PACKED_TVAL_POSSIBLE +#if !defined(DUK_STRCMP) +#define DUK_STRCMP strcmp #endif - -/* PPC32: packed always possible */ -#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_F_PPC32) -#define DUK_USE_PACKED_TVAL_POSSIBLE +#if !defined(DUK_STRNCMP) +#define DUK_STRNCMP strncmp #endif - -/* With Emscripten, force unpacked duk_tval just to be safe, as it seems to - * break at least on Firefox (probably IEEE double arithmetic is not 100% - * supported, especially for NaNs). - */ -#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_F_EMSCRIPTEN) -#undef DUK_USE_PACKED_TVAL_POSSIBLE +#if !defined(DUK_PRINTF) +#define DUK_PRINTF printf #endif - -/* Microsoft Visual Studio 2010 on x64 fails the above rules and tries to - * use a packed type. Force unpacked on x64 in general. - */ -#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_F_X64) -#undef DUK_USE_PACKED_TVAL_POSSIBLE +#if !defined(DUK_FPRINTF) +#define DUK_FPRINTF fprintf #endif - -/* GCC/clang inaccurate math would break compliance and probably duk_tval, - * so refuse to compile. Relax this if -ffast-math is tested to work. - */ -#if defined(__FAST_MATH__) -#error __FAST_MATH__ defined, refusing to compile +#if !defined(DUK_SPRINTF) +#define DUK_SPRINTF sprintf +#endif +#if !defined(DUK_SNPRINTF) +/* snprintf() is technically not part of C89 but usually available. */ +#define DUK_SNPRINTF snprintf +#endif +#if !defined(DUK_VSPRINTF) +#define DUK_VSPRINTF vsprintf +#endif +#if !defined(DUK_VSNPRINTF) +/* vsnprintf() is technically not part of C89 but usually available. */ +#define DUK_VSNPRINTF vsnprintf +#endif +#if !defined(DUK_SSCANF) +#define DUK_SSCANF sscanf +#endif +#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 -/* - * Detection of double constants and math related functions. Availability - * of constants and math functions is a significant porting concern. - * - * INFINITY/HUGE_VAL is problematic on GCC-3.3: it causes an overflow warning - * and there is no pragma in GCC-3.3 to disable it. Using __builtin_inf() - * avoids this problem for some reason. - */ - +#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 #if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600) /* GCC older than 4.6: avoid overflow warnings related to using INFINITY */ @@ -1559,11 +1988,12 @@ typedef struct duk_hthread duk_context; * Use a computed infinity (initialized when a heap is created at the * latest). */ -extern double duk_computed_infinity; #define DUK_USE_COMPUTED_INFINITY #define DUK_DOUBLE_INFINITY duk_computed_infinity #endif +#endif +#if !defined(DUK_DOUBLE_NAN) #undef DUK_USE_COMPUTED_NAN #if defined(NAN) #define DUK_DOUBLE_NAN NAN @@ -1575,10 +2005,10 @@ extern double duk_computed_infinity; * Use a computed NaN (initialized when a heap is created at the * latest). */ -extern double duk_computed_nan; #define DUK_USE_COMPUTED_NAN #define DUK_DOUBLE_NAN duk_computed_nan #endif +#endif /* Many platforms are missing fpclassify() and friends, so use replacements * if necessary. The replacement constants (FP_NAN etc) can be anything but @@ -1670,23 +2100,57 @@ extern double duk_computed_nan; * completeness. Because these are used as function pointers, they need * to be defined as concrete C functions (not macros). */ +#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 +#if !defined(DUK_CEIL) #define DUK_CEIL ceil +#endif +#if !defined(DUK_FMOD) #define DUK_FMOD fmod +#endif +#if !defined(DUK_POW) #define DUK_POW pow +#endif +#if !defined(DUK_ACOS) #define DUK_ACOS acos +#endif +#if !defined(DUK_ASIN) #define DUK_ASIN asin +#endif +#if !defined(DUK_ATAN) #define DUK_ATAN atan +#endif +#if !defined(DUK_ATAN2) #define DUK_ATAN2 atan2 +#endif +#if !defined(DUK_SIN) #define DUK_SIN sin +#endif +#if !defined(DUK_COS) #define DUK_COS cos +#endif +#if !defined(DUK_TAN) #define DUK_TAN tan +#endif +#if !defined(DUK_EXP) #define DUK_EXP exp +#endif +#if !defined(DUK_LOG) #define DUK_LOG log +#endif +#if !defined(DUK_SQRT) #define DUK_SQRT sqrt +#endif /* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, * see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround. @@ -1709,7 +2173,7 @@ extern double duk_computed_nan; * The problem goes away by adding 'volatile' to the datetime computations. * Not sure what the actual triggering conditions are, but using this on * non-C99 systems solves the known issues and has relatively little cost - * on other platforms. See bugs/issue-2e9d9c2d761dabaf8136c0897b91a270d1a47147.yaml. + * on other platforms. */ #undef DUK_USE_PARANOID_DATE_COMPUTATION #if !defined(DUK_F_C99) @@ -1717,125 +2181,182 @@ extern double duk_computed_nan; #endif /* - * ANSI C string/memory function wrapper defines to allow easier workarounds. - * Also convenience macros like DUK_MEMZERO which may be mapped to existing - * platform function to zero memory (like the deprecated bzero). - * - * For instance, some platforms don't support zero-size memcpy correctly, - * some arcane uclibc versions have a buggy memcpy (but working memmove) - * and so on. Such broken platforms can be dealt with here. - * - * NOTE: ANSI C (various versions) and some implementations require that the - * pointer arguments to memset(), memcpy(), and memmove() be valid values - * even when byte size is 0 (even a NULL pointer is considered invalid in - * this context). Zero-size operations as such are allowed, as long as their - * pointer arguments point to a valid memory area. The DUK_MEMSET(), - * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.: - * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be - * allowed. If these are not fulfilled, a macro wrapper is needed. - * - * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 - * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html + * Byte order and double memory layout detection * - * Not sure what's the required behavior when a pointer points just past the - * end of a buffer, which often happens in practice (e.g. zero size memmoves). - * For example, if allocation size is 3, the following pointer would not - * technically point to a valid memory byte: + * Endianness detection is a major portability hassle because the macros + * and headers are not standardized. There's even variance across UNIX + * platforms. Even with "standard" headers, details like underscore count + * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used + * (Crossbridge has a single underscore, for instance). * - * <-- alloc --> - * | 0 | 1 | 2 | ..... - * ^-- p=3, points after last valid byte (2) + * The checks below are structured with this in mind: several approaches are + * used, and at the end we check if any of them worked. This allows generic + * approaches to be tried first, and platform/compiler specific hacks tried + * last. As a last resort, the user can force a specific endianness, as it's + * not likely that automatic detection will work on the most exotic platforms. * - * If this is a practical issue, wrappers are again needed. - */ - -typedef FILE duk_file; -#define DUK_STDIN stdin -#define DUK_STDOUT stdout -#define DUK_STDERR stderr - -/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h - * (which is unfortunately named). + * Duktape supports little and big endian machines. There's also support + * for a hybrid used by some ARM machines where integers are little endian + * but IEEE double values use a mixed order (12345678 -> 43218765). This + * byte order for doubles is referred to as "mixed endian". */ -#define DUK_ANSI_MALLOC malloc -#define DUK_ANSI_REALLOC realloc -#define DUK_ANSI_CALLOC calloc -#define DUK_ANSI_FREE free -/* Old uclibcs have a broken memcpy so use memmove instead (this is overly - * wide now on purpose): - * http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html +/* 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_F_UCLIBC) -#define DUK_MEMCPY memmove +#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 -#define DUK_MEMCPY memcpy +#error invalid DUK_OPT_FORCE_BYTEORDER value #endif +#endif /* DUK_OPT_FORCE_BYTEORDER */ -#define DUK_MEMMOVE memmove -#define DUK_MEMCMP memcmp -#define DUK_MEMSET memset -#define DUK_STRLEN strlen -#define DUK_STRCMP strcmp -#define DUK_STRNCMP strncmp -#define DUK_PRINTF printf -#define DUK_FPRINTF fprintf -#define DUK_SPRINTF sprintf +/* 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 + * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang. + * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html + */ +#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) +#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 +#else +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER__) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit + * integer ordering and is not relevant. + */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */ -#if defined(DUK_F_MSVC) -/* _snprintf() does NOT NUL terminate on truncation, but Duktape code never - * assumes that. - * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 +/* More or less standard endianness predefines provided by header files. + * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER + * will be big endian, see: http://lists.mysql.com/internals/443. + * On some platforms some defines may be present with an empty value which + * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453. */ -#define DUK_SNPRINTF _snprintf +#if !defined(DUK_USE_BYTEORDER) +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ + defined(__LITTLE_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) +#define DUK_USE_BYTEORDER 1 +#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 2 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 1 #else -#define DUK_SNPRINTF snprintf +/* Byte order is little endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ + defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ + defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) +#define DUK_USE_BYTEORDER 3 +#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) +/* Float word order not known, assume not a hybrid. */ +#define DUK_USE_BYTEORDER 3 +#else +/* Byte order is big endian but cannot determine IEEE double word order. */ +#endif /* float word order */ +#else +/* Cannot determine byte order. */ +#endif /* integer byte order */ +#endif /* !defined(DUK_USE_BYTEORDER) */ + +/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: + * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - = 20500L) -/* since gcc-2.5 */ -#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -#elif defined(__clang__) -/* syntax same as gcc */ -#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -#elif defined(DUK_F_MSVC) -/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ -#define DUK_NORETURN(decl) __declspec(noreturn) decl -#else -/* Don't know how to declare a noreturn function, so don't do it; this - * may cause some spurious compilation warnings (e.g. "variable used - * uninitialized"). +#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. */ -#define DUK_NORETURN(decl) decl +#define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0) #endif - -/* - * Macro for stating that a certain line cannot be reached. - * - * http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Other-Builtins.html#Other-Builtins - * http://clang.llvm.org/docs/LanguageExtensions.html +#if !defined(DUK_UNREF) +/* Macro for suppressing warnings for potentially unreferenced variables. + * The variables can be actually unreferenced or unreferenced in some + * specific cases only; for instance, if a variable is only debug printed, + * it is unreferenced when debug printing is disabled. */ - -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -/* since gcc-4.5 */ -#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while(0) -#elif defined(__clang__) && defined(__has_builtin) -#if __has_builtin(__builtin_unreachable) -/* same as gcc */ -#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while(0) +#define DUK_UNREF(x) do { (void) (x); } while (0) #endif -#else -/* unknown */ +#if !defined(DUK_NORETURN) +#define DUK_NORETURN(decl) decl #endif - #if !defined(DUK_UNREACHABLE) /* Don't know how to declare unreachable point, so don't do it; this * may cause some spurious compilation warnings (e.g. "variable used * uninitialized"). - */ -#define DUK_UNREACHABLE() /* unreachable */ -#endif - -/* - * Likely and unlikely branches. Using these is not at all a clear cut case, - * so the selection is a two-step process: (1) DUK_USE_BRANCH_HINTS is set - * if the architecture, compiler etc make it useful to use the hints, and (2) - * a separate check determines how to do them. - * - * These macros expect the argument to be a relational expression with an - * integer value. If used with pointers, you should use an explicit check - * like: - * - * if (DUK_LIKELY(ptr != NULL)) { ... } - * - * instead of: - * - * if (DUK_LIKELY(ptr)) { ... } - * - * http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html (__builtin_expect) - */ - -/* pretty much a placeholder now */ -#if defined(DUK_F_GCC) -#define DUK_USE_BRANCH_HINTS -#elif defined(DUK_F_CLANG) -#define DUK_USE_BRANCH_HINTS -#else -#undef DUK_USE_BRANCH_HINTS -#endif - -#if defined(DUK_USE_BRANCH_HINTS) -#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -/* GCC: test not very accurate; enable only in relatively recent builds - * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) - */ -#define DUK_LIKELY(x) __builtin_expect((x), 1) -#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -#elif defined(DUK_F_CLANG) -#define DUK_LIKELY(x) __builtin_expect((x), 1) -#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -#endif -#endif /* DUK_USE_BRANCH_HINTS */ - -#if !defined(DUK_LIKELY) -#define DUK_LIKELY(x) (x) -#endif -#if !defined(DUK_UNLIKELY) -#define DUK_UNLIKELY(x) (x) -#endif - -/* - * Function inlining control - * - * DUK_NOINLINE: avoid inlining a function. - * DUK_INLINE: suggest inlining a function. - * DUK_ALWAYS_INLINE: force inlining for critical functions. - * - * Apply to function definition only (not declaration). - */ - -#if defined(DUK_F_CLANG) && (defined(DUK_F_C99) || defined(DUK_F_CPP11)) -#define DUK_NOINLINE __attribute__((noinline)) -#define DUK_INLINE inline -#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -#elif defined(DUK_F_GCC) && defined(DUK_F_GCC_VERSION) && (defined(DUK_F_C99) || defined(DUK_F_CPP11)) -#if (DUK_F_GCC_VERSION >= 30101) -#define DUK_NOINLINE __attribute__((noinline)) -#define DUK_INLINE inline -#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) + */ +#define DUK_UNREACHABLE() do { } while (0) #endif +#if !defined(DUK_LOSE_CONST) +/* Convert any input pointer into a "void *", losing a const qualifier. + * This is not fully portable because casting through duk_uintptr_t may + * not work on all architectures (e.g. those with long, segmented pointers). + */ +#define DUK_LOSE_CONST(src) ((void *) (duk_uintptr_t) (src)) #endif -#if !defined(DUK_NOINLINE) -#define DUK_NOINLINE /*nop*/ -#define DUK_INLINE /*nop*/ -#define DUK_ALWAYS_INLINE /*nop*/ +#if !defined(DUK_LIKELY) +#define DUK_LIKELY(x) (x) +#endif +#if !defined(DUK_UNLIKELY) +#define DUK_UNLIKELY(x) (x) #endif -/* Temporary workaround for GH-323: avoid inlining control when - * compiling from multiple sources, as it causes compiler trouble. - */ -#if !defined(DUK_SINGLE_FILE) -#undef DUK_NOINLINE -#undef DUK_INLINE -#undef DUK_ALWAYS_INLINE +#if !defined(DUK_NOINLINE) #define DUK_NOINLINE /*nop*/ +#endif +#if !defined(DUK_INLINE) #define DUK_INLINE /*nop*/ +#endif +#if !defined(DUK_ALWAYS_INLINE) #define DUK_ALWAYS_INLINE /*nop*/ #endif -/* - * Symbol visibility macros - * - * To avoid C++ declaration issues (see GH-63): - * - * - Don't use DUK_LOCAL_DECL for local -data symbols- so that you don't - * end up with both a "static" declaration and a definition. - * - * - Wrap any DUK_INTERNAL_DECL with a '#if !defined(DUK_SINGLE_FILE)' - * so that the internal declarations (which would map to "static" in - * a single file distribution) get dropped. - */ - -/* XXX: user override for these? user override for just using the default visibility macros? */ -/* XXX: separate macros for function and data may be necessary at some point. */ - -#if defined(DUK_F_GCC_VERSION) -#if (DUK_F_GCC_VERSION >= 40000) && !(defined(DUK_F_MINGW) || defined(DUK_F_CYGWIN)) -/* Might work on earlier versions too but limit to GCC 4+. - * MinGW should use Windows specific __declspec or no visibility attributes at all, - * otherwise: "warning: visibility attribute not supported in this configuration; ignored". - * Same applies to Cygwin GCC. - */ -#define DUK_F_GCC_SYMBOL_VISIBILITY -#endif -#endif -#if defined(DUK_F_CLANG) && !defined(DUK_F_GCC_SYMBOL_VISIBILITY) -#define DUK_F_GCC_SYMBOL_VISIBILITY +#if !defined(DUK_EXTERNAL_DECL) +#define DUK_EXTERNAL_DECL extern #endif -#if defined(DUK_OPT_DLL_BUILD) && defined(_WIN32) && (defined(_MSC_VER) || defined(__GNUC__)) -/* __declspec(dllexport) and __declspec(dllimport) only for Windows DLL build. - * MSVC: any minimum version? - * MinGW: no minimum version, even gcc-2.95.3 supported dllimport/dllexport. -*/ -#define DUK_F_MSVC_DLL_SYMBOL_VISIBILITY +#if !defined(DUK_EXTERNAL) +#define DUK_EXTERNAL /*empty*/ #endif - -#if defined(DUK_F_GCC_SYMBOL_VISIBILITY) -/* GCC 4+ visibility attributes. */ -#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern -#define DUK_EXTERNAL __attribute__ ((visibility("default"))) +#if !defined(DUK_INTERNAL_DECL) #if defined(DUK_SINGLE_FILE) #define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static #else -#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern -#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) +#define DUK_INTERNAL_DECL extern #endif -#elif defined(DUK_F_MSVC_DLL_SYMBOL_VISIBILITY) -/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're - * compiling Duktape or the application. - */ -#if defined(DUK_COMPILING_DUKTAPE) -#define DUK_EXTERNAL_DECL extern __declspec(dllexport) -#define DUK_EXTERNAL __declspec(dllexport) -#else -#define DUK_EXTERNAL_DECL extern __declspec(dllimport) -#define DUK_EXTERNAL should_not_happen #endif +#if !defined(DUK_INTERNAL) #if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static #define DUK_INTERNAL static #else -#define DUK_INTERNAL_DECL extern -#define DUK_INTERNAL /*empty*/ -#endif -#else -/* Default visibility. */ -#define DUK_EXTERNAL_DECL extern -#define DUK_EXTERNAL /*empty*/ -#if defined(DUK_SINGLE_FILE) -#define DUK_INTERNAL_DECL static -#define DUK_INTERNAL static -#else /* DUK_SINGLE_FILE */ -#define DUK_INTERNAL_DECL extern #define DUK_INTERNAL /*empty*/ #endif #endif - -/* For now, these are shared. */ +#if !defined(DUK_LOCAL_DECL) #define DUK_LOCAL_DECL static +#endif +#if !defined(DUK_LOCAL) #define DUK_LOCAL static +#endif -/* - * __FILE__, __LINE__, __func__ are wrapped. Especially __func__ is a - * problem because it is not available even in some compilers which try - * to be C99 compatible (e.g. VBCC with -c99 option). - */ - +#if !defined(DUK_FILE_MACRO) #define DUK_FILE_MACRO __FILE__ - +#endif +#if !defined(DUK_LINE_MACRO) #define DUK_LINE_MACRO __LINE__ - -#if !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) +#endif +#if !defined(DUK_FUNC_MACRO) +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) #define DUK_FUNC_MACRO __func__ +#elif defined(__FUNCTION__) +#define DUK_FUNC_MACRO __FUNCTION__ #else #define DUK_FUNC_MACRO "unknown" #endif +#endif -/* - * Byteswap macros - * - * These are here so that inline assembly or other platform functions can be - * used if available. - */ - +#if !defined(DUK_BSWAP32) #define DUK_BSWAP32(x) \ ((((duk_uint32_t) (x)) >> 24) | \ ((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \ ((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \ (((duk_uint32_t) (x)) << 24)) - +#endif +#if !defined(DUK_BSWAP16) #define DUK_BSWAP16(x) \ ((duk_uint16_t) (x) >> 8) | \ ((duk_uint16_t) (x) << 8) - -/* - * Architecture string, human readable value exposed in Duktape.env - */ - -#if defined(DUK_F_X86) -#define DUK_USE_ARCH_STRING "x86" -#elif defined(DUK_F_X32) -#define DUK_USE_ARCH_STRING "x32" -#elif defined(DUK_F_X64) -#define DUK_USE_ARCH_STRING "x64" -#elif defined(DUK_F_ARM) -#define DUK_USE_ARCH_STRING "arm" -#elif defined(DUK_F_MIPS32) -#define DUK_USE_ARCH_STRING "mips32" -#elif defined(DUK_F_MIPS64) -#define DUK_USE_ARCH_STRING "mips64" -#elif defined(DUK_F_SUPERH) -#define DUK_USE_ARCH_STRING "sh" -#elif defined(DUK_F_PPC) -#define DUK_USE_ARCH_STRING "ppc" -#elif defined(DUK_F_M68K) -#define DUK_USE_ARCH_STRING "m68k" -#elif defined(DUK_F_FLASHPLAYER) -#define DUK_USE_ARCH_STRING "flashplayer" -#elif defined(DUK_F_EMSCRIPTEN) -#define DUK_USE_ARCH_STRING "emscripten" -#else -#define DUK_USE_ARCH_STRING "unknown" #endif -/* - * OS string, human readable value exposed in Duktape.env - */ +/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ +#if !defined(DUK_F_VARIADIC_MACROS_PROVIDED) +#undef DUK_USE_VARIADIC_MACROS +#if defined(DUK_F_C99) || defined(DUK_F_CPP11) +#define DUK_USE_VARIADIC_MACROS +#endif +#endif -#if defined(DUK_F_LINUX) -#define DUK_USE_OS_STRING "linux" -#elif defined(__APPLE__) -/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ -#if TARGET_IPHONE_SIMULATOR -#define DUK_USE_OS_STRING "iphone-sim" -#elif TARGET_OS_IPHONE -#define DUK_USE_OS_STRING "iphone" -#elif TARGET_OS_MAC -#define DUK_USE_OS_STRING "ios" +#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE)) +#if defined(DUK_F_C99) +#define DUK_USE_FLEX_C99 #else -#define DUK_USE_OS_STRING "ios-unknown" +#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */ #endif -#elif defined(DUK_F_FREEBSD) -#define DUK_USE_OS_STRING "freebsd" -#elif defined(DUK_F_OPENBSD) -#define DUK_USE_OS_STRING "openbsd" -#elif defined(DUK_F_NETBSD) -#define DUK_USE_OS_STRING "netbsd" -#elif defined(DUK_F_BSD) -#define DUK_USE_OS_STRING "bsd" -#elif defined(DUK_F_UNIX) -#define DUK_USE_OS_STRING "unix" -#elif defined(DUK_F_WINDOWS) -#define DUK_USE_OS_STRING "windows" -#elif defined(DUK_F_TOS) -#define DUK_USE_OS_STRING "tos" -#elif defined(DUK_F_AMIGAOS) -#define DUK_USE_OS_STRING "amigaos" -#elif defined(DUK_F_QNX) -#define DUK_USE_OS_STRING "qnx" -#elif defined(DUK_F_TINSPIRE) -#define DUK_USE_OS_STRING "tinspire" -#else -#define DUK_USE_OS_STRING "unknown" #endif -/* - * Compiler string, human readable value exposed in Duktape.env - */ - -#if defined(DUK_F_MINGW) -#define DUK_USE_COMPILER_STRING "mingw" -#elif defined(DUK_F_GCC) -#if defined(DUK_F_CPP) -#define DUK_USE_COMPILER_STRING "g++" -#else -#define DUK_USE_COMPILER_STRING "gcc" +#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \ + defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER)) +#define DUK_USE_PACK_DUMMY_MEMBER #endif -#elif defined(DUK_F_CLANG) -#define DUK_USE_COMPILER_STRING "clang" -#elif defined(DUK_F_MSVC) -#define DUK_USE_COMPILER_STRING "msvc" -#elif defined(DUK_F_VBCC) -#define DUK_USE_COMPILER_STRING "vbcc" -#else -#define DUK_USE_COMPILER_STRING "unknown" + +#if 0 /* not defined by default */ +#undef DUK_USE_GCC_PRAGMAS #endif -/* - * Target info string +/* Workaround for GH-323: avoid inlining control when compiling from + * multiple sources, as it causes compiler portability trouble. */ - -#if defined(DUK_OPT_TARGET_INFO) -#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO -#else -#define DUK_USE_TARGET_INFO "unknown" +#if !defined(DUK_SINGLE_FILE) +#undef DUK_NOINLINE +#undef DUK_INLINE +#undef DUK_ALWAYS_INLINE +#define DUK_NOINLINE /*nop*/ +#define DUK_INLINE /*nop*/ +#define DUK_ALWAYS_INLINE /*nop*/ #endif /* - * Long control transfer, setjmp/longjmp or alternatives - * - * Signal mask is not saved (when that can be communicated to the platform) + * Check whether or not a packed duk_tval representation is possible. + * What's basically required is that pointers are 32-bit values + * (sizeof(void *) == 4). Best effort check, not always accurate. + * If guess goes wrong, crashes may result; self tests also verify + * the guess. */ -/* dummy non-zero value to be used as an argument for longjmp(), see man longjmp */ -#define DUK_LONGJMP_DUMMY_VALUE 1 +/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ +#if !defined(DUK_F_PACKED_TVAL_PROVIDED) +#undef DUK_F_PACKED_TVAL_POSSIBLE -#if defined(DUK_OPT_SETJMP) -#define DUK_USE_SETJMP -#elif defined(DUK_OPT_UNDERSCORE_SETJMP) -#define DUK_USE_UNDERSCORE_SETJMP -#elif defined(DUK_OPT_SIGSETJMP) -#define DUK_USE_SIGSETJMP -#elif defined(__APPLE__) -/* Use _setjmp() on Apple by default, see GH-55. */ -#define DUK_USE_UNDERSCORE_SETJMP -#else -/* The most portable default is setjmp(). */ -#define DUK_USE_SETJMP +/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif #endif -#if defined(DUK_USE_UNDERSCORE_SETJMP) -#define DUK_SETJMP(jb) _setjmp((jb)) -#define DUK_LONGJMP(jb) _longjmp((jb), DUK_LONGJMP_DUMMY_VALUE) -#elif defined(DUK_USE_SIGSETJMP) -#define DUK_SETJMP(jb) sigsetjmp((jb), 0 /*savesigs*/) -#define DUK_LONGJMP(jb) siglongjmp((jb), DUK_LONGJMP_DUMMY_VALUE) -#elif defined(DUK_USE_SETJMP) -#define DUK_SETJMP(jb) setjmp((jb)) -#define DUK_LONGJMP(jb) longjmp((jb), DUK_LONGJMP_DUMMY_VALUE) -#else -#error internal error +/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) +#if (DUK_UINTPTR_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif #endif -/* - * Speed/size and other performance options - */ +/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ +#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) +#if (DUK_SIZE_MAX <= 0xffffffffUL) +#define DUK_F_PACKED_TVAL_POSSIBLE +#endif +#endif -/* Use fast ("inline") refcount operations instead of calling out to helpers - * by default. The difference in binary size is small (~1kB on x64). - */ -#define DUK_USE_FAST_REFCOUNT_DEFAULT +#undef DUK_USE_PACKED_TVAL +#if defined(DUK_F_PACKED_TVAL_POSSIBLE) +#define DUK_USE_PACKED_TVAL +#endif -/* Assert for valstack space but don't check for it in non-assert build. - * Valstack overruns (writing beyond checked space) is memory unsafe and - * potentially a segfault. Produces a smaller and faster binary. - * (In practice the speed difference is small with -O3 so default to - * safer behavior for now.) - */ -#undef DUK_USE_VALSTACK_UNSAFE +#undef DUK_F_PACKED_TVAL_POSSIBLE +#endif /* DUK_F_PACKED_TVAL_PROVIDED */ -/* Catch-all flag which can be used to choose between variant algorithms - * where a speed-size tradeoff exists (e.g. lookup tables). When it really - * matters, specific use flags may be appropriate. +/* 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 + * having mostly aligned accesses. */ -#undef DUK_USE_PREFER_SIZE - -/* Use a sliding window for lexer; slightly larger footprint, slightly faster. */ -#define DUK_USE_LEXER_SLIDING_WINDOW +#undef DUK_USE_HOBJECT_LAYOUT_1 +#undef DUK_USE_HOBJECT_LAYOUT_2 +#undef DUK_USE_HOBJECT_LAYOUT_3 +#if (DUK_USE_ALIGN_BY == 1) +/* On platforms without any alignment issues, layout 1 is preferable + * because it compiles to slightly less code and provides direct access + * to property keys. + */ +#define DUK_USE_HOBJECT_LAYOUT_1 +#else +/* On other platforms use layout 2, which requires some padding but + * is a bit more natural than layout 3 in ordering the entries. Layout + * 3 is currently not used. + */ +#define DUK_USE_HOBJECT_LAYOUT_2 +#endif -/* Transparent JSON.stringify() fastpath. */ -#undef DUK_USE_JSON_STRINGIFY_FASTPATH -#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH) -#define DUK_USE_JSON_STRINGIFY_FASTPATH +/* GCC/clang inaccurate math would break compliance and probably duk_tval, + * so refuse to compile. Relax this if -ffast-math is tested to work. + */ +#if defined(__FAST_MATH__) +#error __FAST_MATH__ defined, refusing to compile #endif /* - * Tagged type representation (duk_tval) + * Feature option handling */ -#undef DUK_USE_PACKED_TVAL -#undef DUK_USE_FULL_TVAL +#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_USE_PACKED_TVAL_POSSIBLE) && !defined(DUK_OPT_NO_PACKED_TVAL) -#define DUK_USE_PACKED_TVAL +#if defined(DUK_OPT_ASSERTIONS) +#define DUK_USE_ASSERTIONS +#elif defined(DUK_OPT_NO_ASSERTIONS) +#undef DUK_USE_ASSERTIONS +#else +#undef DUK_USE_ASSERTIONS #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 +#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 -#define DUK_USE_FASTINT + +#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 -/* - * Memory management options - */ - -#define DUK_USE_REFERENCE_COUNTING -#define DUK_USE_DOUBLE_LINKED_HEAP -#define DUK_USE_MARK_AND_SWEEP -#define DUK_USE_MS_STRINGTABLE_RESIZE +#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_NO_REFERENCE_COUNTING) -#undef DUK_USE_REFERENCE_COUNTING -#undef DUK_USE_DOUBLE_LINKED_HEAP -/* XXX: undef DUK_USE_MS_STRINGTABLE_RESIZE as it is more expensive - * with more frequent mark-and-sweeps? - */ +#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_BUFFEROBJECT_SUPPORT #endif -#if defined(DUK_OPT_NO_MARK_AND_SWEEP) -#undef DUK_USE_MARK_AND_SWEEP +#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_USE_MARK_AND_SWEEP) -#define DUK_USE_VOLUNTARY_GC -#if defined(DUK_OPT_NO_VOLUNTARY_GC) -#undef DUK_USE_VOLUNTARY_GC +#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_USE_MARK_AND_SWEEP) && !defined(DUK_USE_REFERENCE_COUNTING) -#error must have either mark-and-sweep or reference counting enabled +#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_NO_MS_STRINGTABLE_RESIZE) -#undef DUK_USE_MS_STRINGTABLE_RESIZE +#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 -#undef DUK_USE_GC_TORTURE -#if defined(DUK_OPT_GC_TORTURE) -#define DUK_USE_GC_TORTURE +#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 -/* - * String table options - */ +#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_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE) -/* Low memory algorithm: separate chaining using arrays, fixed size hash */ -#define DUK_USE_STRTAB_CHAIN -#define DUK_USE_STRTAB_CHAIN_SIZE DUK_OPT_STRTAB_CHAIN_SIZE +#if defined(DUK_OPT_DDPRINT) +#define DUK_USE_DDPRINT +#elif defined(DUK_OPT_NO_DDPRINT) +#undef DUK_USE_DDPRINT #else -/* Default algorithm: open addressing (probing) */ -#define DUK_USE_STRTAB_PROBE +#undef DUK_USE_DDPRINT #endif -/* - * Error handling options - */ +#if defined(DUK_OPT_DEBUG) +#define DUK_USE_DEBUG +#elif defined(DUK_OPT_NO_DEBUG) +#undef DUK_USE_DEBUG +#else +#undef DUK_USE_DEBUG +#endif -#define DUK_USE_AUGMENT_ERROR_CREATE -#define DUK_USE_AUGMENT_ERROR_THROW -#define DUK_USE_TRACEBACKS -#define DUK_USE_ERRCREATE -#define DUK_USE_ERRTHROW +#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 -#define DUK_USE_VERBOSE_ERRORS +#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_NO_AUGMENT_ERRORS) -#undef DUK_USE_AUGMENT_ERROR_CREATE -#undef DUK_USE_AUGMENT_ERROR_THROW -#undef DUK_USE_TRACEBACKS -#undef DUK_USE_ERRCREATE -#undef DUK_USE_ERRTHROW -#elif defined(DUK_OPT_NO_TRACEBACKS) -#undef DUK_USE_TRACEBACKS +#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_NO_VERBOSE_ERRORS) -#undef DUK_USE_VERBOSE_ERRORS +#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_USE_TRACEBACKS) -#if defined(DUK_OPT_TRACEBACK_DEPTH) -#define DUK_USE_TRACEBACK_DEPTH DUK_OPT_TRACEBACK_DEPTH +#if defined(DUK_OPT_DEBUGGER_SUPPORT) +#define DUK_USE_DEBUGGER_SUPPORT +#elif defined(DUK_OPT_NO_DEBUGGER_SUPPORT) +#undef DUK_USE_DEBUGGER_SUPPORT #else -#define DUK_USE_TRACEBACK_DEPTH 10 +#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 +#undef DUK_USE_DEBUGGER_THROW_NOTIFY #endif -/* Include messages in executor internal errors. */ -#define DUK_USE_VERBOSE_EXECUTOR_ERRORS +#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 -/* - * Execution and debugger options - */ +#if defined(DUK_OPT_DEBUG_BUFSIZE) +#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE +#else +#define DUK_USE_DEBUG_BUFSIZE 65536L +#endif -#undef DUK_USE_INTERRUPT_COUNTER -#if defined(DUK_OPT_INTERRUPT_COUNTER) -#define DUK_USE_INTERRUPT_COUNTER +#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_DOUBLE_LINKED_HEAP #endif -#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)) +#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 -#undef DUK_USE_DEBUGGER_SUPPORT -#if defined(DUK_OPT_DEBUGGER_SUPPORT) -#define DUK_USE_DEBUGGER_SUPPORT +#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 -#undef DUK_USE_DEBUGGER_FWD_PRINTALERT -#if defined(DUK_OPT_DEBUGGER_SUPPORT) && defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT) -#define DUK_USE_DEBUGGER_FWD_PRINTALERT +#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 -#undef DUK_USE_DEBUGGER_FWD_LOGGING -#if defined(DUK_OPT_DEBUGGER_SUPPORT) && defined(DUK_OPT_DEBUGGER_FWD_LOGGING) -#define DUK_USE_DEBUGGER_FWD_LOGGING +#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_ERRCREATE #endif -/* DumpHeap is optional because it's not always needed and has a relatively - * large footprint. - */ -#undef DUK_USE_DEBUGGER_DUMPHEAP -#if defined(DUK_OPT_DEBUGGER_DUMPHEAP) -#define DUK_USE_DEBUGGER_DUMPHEAP +#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 -#define DUK_USE_DEBUGGER_THROW_NOTIFY -#if defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY) -#undef DUK_USE_DEBUGGER_THROW_NOTIFY +#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_OBJECT_PROTO_PROPERTY #endif -#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT -#if defined(DUK_OPT_DEBUGGER_PAUSE_UNCAUGHT) -#define DUK_USE_DEBUGGER_PAUSE_UNCAUGHT +#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 -/* Debugger transport read/write torture. */ -#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE -#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE) -#define DUK_USE_DEBUGGER_TRANSPORT_TORTURE +#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 -/* For opcodes with indirect indices, check final index against stack size. - * This should not be necessary because the compiler is trusted, and we don't - * bound check non-indirect indices either. - */ #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 -/* - * Debug printing and assertion options - */ +#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_DEBUG -#undef DUK_USE_DPRINT -#undef DUK_USE_DDPRINT -#undef DUK_USE_DDDPRINT -#undef DUK_USE_DPRINT_RDTSC -#undef DUK_USE_ASSERTIONS +#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 -/* Global debug enable. Compile must be clean on C99 regardless of whether or - * not debugging is enabled. On non-C99 platforms compile should be clean with - * debugging disabled but may produce warnings with debugging enabled (related - * to debug macro hackery and such). - */ -#if defined(DUK_OPT_DEBUG) -#define DUK_USE_DEBUG +#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 -#if defined(DUK_OPT_DEBUG) && defined(DUK_OPT_DPRINT) -#define DUK_USE_DPRINT +/* 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 -#if defined(DUK_OPT_DEBUG) && defined(DUK_OPT_DDPRINT) -#define DUK_USE_DDPRINT +#define DUK_USE_FASTINT #endif -#if defined(DUK_OPT_DEBUG) && defined(DUK_OPT_DDDPRINT) -#define DUK_USE_DDDPRINT + +#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 -#undef DUK_USE_DPRINT_COLORS -#if defined(DUK_OPT_DPRINT_COLORS) -#define DUK_USE_DPRINT_COLORS +#if defined(DUK_OPT_FUNCPTR16) +#define DUK_USE_FUNCPTR16 +#elif defined(DUK_OPT_NO_FUNCPTR16) +#undef DUK_USE_FUNCPTR16 +#else +#undef DUK_USE_FUNCPTR16 #endif -#if defined(DUK_USE_RDTSC) && defined(DUK_OPT_DPRINT_RDTSC) -#define DUK_USE_DPRINT_RDTSC +#if defined(DUK_OPT_FUNCPTR_DEC16) +#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr)) #else -#undef DUK_USE_DPRINT_RDTSC +#undef DUK_USE_FUNCPTR_DEC16 #endif -#if defined(DUK_OPT_ASSERTIONS) -#define DUK_USE_ASSERTIONS +#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 +#undef DUK_USE_GC_TORTURE #endif -/* The static buffer for debug printing is quite large by default, so there - * is an option to shrink it manually for constrained builds. - */ -#if defined(DUK_OPT_DEBUG_BUFSIZE) -#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE +#if defined(DUK_OPT_HEAPPTR16) +#define DUK_USE_HEAPPTR16 +#elif defined(DUK_OPT_NO_HEAPPTR16) +#undef DUK_USE_HEAPPTR16 #else -#define DUK_USE_DEBUG_BUFSIZE 65536L +#undef DUK_USE_HEAPPTR16 #endif -/* - * Ecmascript features / compliance options - */ - -#if defined(DUK_F_BCC) -/* Math built-in is stubbed out on BCC to allow compiler torture testing. */ +#if defined(DUK_OPT_HEAPPTR_DEC16) +#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr)) #else -#define DUK_USE_MATH_BUILTIN +#undef DUK_USE_HEAPPTR_DEC16 #endif -#define DUK_USE_STRICT_DECL -#if defined(DUK_OPT_NO_STRICT_DECL) -#undef DUK_USE_STRICT_DECL +#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 -#define DUK_USE_REGEXP_SUPPORT -#if defined(DUK_OPT_NO_REGEXP_SUPPORT) -#undef DUK_USE_REGEXP_SUPPORT +/* For now, hash part is dropped if and only if 16-bit object fields are used. */ +#define DUK_USE_HOBJECT_HASH_PART +#if defined(DUK_OPT_OBJSIZES16) +#undef DUK_USE_HOBJECT_HASH_PART #endif -#undef DUK_USE_STRICT_UTF8_SOURCE -#if defined(DUK_OPT_STRICT_UTF8_SOURCE) -#define DUK_USE_STRICT_UTF8_SOURCE +#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 -#define DUK_USE_OCTAL_SUPPORT -#if defined(DUK_OPT_NO_OCTAL_SUPPORT) -#undef DUK_USE_OCTAL_SUPPORT +#if defined(DUK_OPT_INTERRUPT_COUNTER) +#define DUK_USE_INTERRUPT_COUNTER +#elif defined(DUK_OPT_NO_INTERRUPT_COUNTER) +#undef DUK_USE_INTERRUPT_COUNTER +#else +#undef DUK_USE_INTERRUPT_COUNTER #endif -#define DUK_USE_SOURCE_NONBMP -#if defined(DUK_OPT_NO_SOURCE_NONBMP) -#undef DUK_USE_SOURCE_NONBMP +#if defined(DUK_OPT_JC) +#define DUK_USE_JC +#elif defined(DUK_OPT_NO_JC) +#undef DUK_USE_JC +#else +#define DUK_USE_JC #endif -#define DUK_USE_BROWSER_LIKE -#if defined(DUK_OPT_NO_BROWSER_LIKE) -#undef DUK_USE_BROWSER_LIKE +#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 +#undef DUK_USE_JSON_STRINGIFY_FASTPATH #endif -/* E5/E5.1 Section B features. */ -#define DUK_USE_SECTION_B -#if defined(DUK_OPT_NO_SECTION_B) -#undef DUK_USE_SECTION_B +#if defined(DUK_OPT_JX) +#define DUK_USE_JX +#elif defined(DUK_OPT_NO_JX) +#undef DUK_USE_JX +#else +#define DUK_USE_JX #endif -/* Non-standard regexp parsing features. */ -#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE +#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) +#define DUK_USE_LIGHTFUNC_BUILTINS +#elif defined(DUK_OPT_NO_LIGHTFUNC_BUILTINS) +#undef DUK_USE_LIGHTFUNC_BUILTINS +#else +#undef DUK_USE_LIGHTFUNC_BUILTINS +#endif -/* Treat function statements (function declarations outside top level of - * Program or FunctionBody) same as normal function declarations. This is - * also V8 behavior. See test-dev-func-decl-outside-top.js. - */ -#define DUK_USE_NONSTD_FUNC_STMT -#if defined(DUK_OPT_NO_NONSTD_FUNC_STMT) -#undef DUK_USE_NONSTD_FUNC_STMT +#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 -/* Array.prototype.splice() non-standard but real world compatible behavior - * when deleteCount is omitted. - */ -#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -#if defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT) -#undef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT +#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 +#define DUK_USE_MS_STRINGTABLE_RESIZE #endif -/* Array.prototype.concat() non-standard but real world compatible behavior - * for non-existent trailing elements. - */ +#if defined(DUK_OPT_NONSTD_ARRAY_CONCAT_TRAILER) #define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -#if defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) +#elif defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER) #undef DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER +#else +#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER #endif -/* Array.prototype.map() non-standard but real world compatible behavior - * for non-existent trailing elements. - */ +#if defined(DUK_OPT_NONSTD_ARRAY_MAP_TRAILER) #define DUK_USE_NONSTD_ARRAY_MAP_TRAILER -#if defined(DUK_OPT_NO_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 -/* Non-standard 'caller' property for function instances, see - * test-bi-function-nonstd-caller-prop.js. - */ -#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) -#define DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -#endif - -/* Non-standard Object.prototype.__proto__ (ES6), see - * test-bi-object-proto-__proto__.js. - */ -#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#if defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY) -#undef DUK_USE_ES6_OBJECT_PROTO_PROPERTY -#endif - -/* Non-standard Object.setPrototypeOf (ES6), see - * test-bi-object-setprototypeof.js. - */ -#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#if defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF) -#undef DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -#endif - -/* ES6 Proxy object (subset for now). */ -#define DUK_USE_ES6_PROXY -#if defined(DUK_OPT_NO_ES6_PROXY) -#undef DUK_USE_ES6_PROXY +#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 -/* Record pc-to-line information. */ -#define DUK_USE_PC2LINE -#if defined(DUK_OPT_NO_PC2LINE) -#undef DUK_USE_PC2LINE +#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 -/* Non-standard function 'source' property. */ -#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY #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 -/* CommonJS modules */ -#define DUK_USE_COMMONJS_MODULES -#if defined(DUK_OPT_NO_COMMONJS_MODULES) -#undef DUK_USE_COMMONJS_MODULES +#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 -/* Additional key argument to setter/getter calls when triggered by property - * accesses. - */ - +#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT) #define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT -#if defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) +#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT) #undef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -#undef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT +#else +#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT #endif -/* JSON escaping of U+2028 and U+2029. - */ - +#if defined(DUK_OPT_NONSTD_JSON_ESC_U2028_U2029) #define DUK_USE_NONSTD_JSON_ESC_U2028_U2029 -#if defined(DUK_OPT_NO_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 -/* Allow 32-bit codepoints in String.fromCharCode. */ -#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT -#if defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT) -#undef DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT +#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 -/* Non-standard array fast path write behavior: when writing to numeric - * indexes of an Array instance, assume Array.prototype doesn't have - * conflicting properties (e.g. a non-writable property "7"). - */ -#define DUK_USE_NONSTD_ARRAY_WRITE -#if defined(DUK_OPT_NO_NONSTD_ARRAY_WRITE) -#undef DUK_USE_NONSTD_ARRAY_WRITE +#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 -/* Node.js Buffer and Khronos/ES6 typed array support. */ -#define DUK_USE_BUFFEROBJECT_SUPPORT -#if defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT) -#undef DUK_USE_BUFFEROBJECT_SUPPORT +#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 -/* - * Optional C API options - */ - -#define DUK_USE_BYTECODE_DUMP_SUPPORT -#if defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT) -#undef DUK_USE_BYTECODE_DUMP_SUPPORT +#if defined(DUK_OPT_OBJSIZES16) +#define DUK_USE_OBJSIZES16 +#elif defined(DUK_OPT_NO_OBJSIZES16) +#undef DUK_USE_OBJSIZES16 +#else +#undef DUK_USE_OBJSIZES16 #endif -/* - * Tailcalls - */ - -/* Tailcalls are enabled by default. The non-standard function 'caller' - * property feature conflicts with tailcalls quite severely so tailcalls - * are disabled if the 'caller' property is enabled. - */ -#define DUK_USE_TAILCALL -#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) -#undef DUK_USE_TAILCALL +#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 -/* - * Ecmascript compiler - */ - -/* Ensure final bytecode never exceeds a certain byte size and never uses - * line numbers above a certain limit. This ensures that there is no need - * to deal with unbounded ranges in e.g. pc2line data structures. For now, - * limits are set so that signed 32-bit values can represent line number - * and byte offset with room to spare. - */ -#define DUK_USE_ESBC_LIMITS -#define DUK_USE_ESBC_MAX_LINENUMBER 0x7fff0000L -#define DUK_USE_ESBC_MAX_BYTES 0x7fff0000L - -#undef DUK_USE_SHUFFLE_TORTURE -#if defined(DUK_OPT_SHUFFLE_TORTURE) -#define DUK_USE_SHUFFLE_TORTURE +#if defined(DUK_OPT_PACKED_TVAL) +#define DUK_USE_PACKED_TVAL +#elif defined(DUK_OPT_NO_PACKED_TVAL) +#undef DUK_USE_PACKED_TVAL +#else +#undef DUK_USE_PACKED_TVAL #endif -/* - * User panic handler, panic exit behavior for default panic handler - */ +#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_ABORT -#undef DUK_USE_PANIC_EXIT #undef DUK_USE_PANIC_SEGFAULT - #if defined(DUK_OPT_SEGFAULT_ON_PANIC) #define DUK_USE_PANIC_SEGFAULT -#else -#define DUK_USE_PANIC_ABORT -#endif - -/* - * File I/O support. This is now used in a few API calls to e.g. push - * a string from file contents or eval a file. For portability it must - * be possible to disable I/O altogether. - */ - -#undef DUK_USE_FILE_IO -#if !defined(DUK_OPT_NO_FILE_IO) -#define DUK_USE_FILE_IO #endif -/* - * Optional run-time self tests executed when a heap is created. Some - * platform/compiler issues cannot be determined at compile time. One - * particular example is the bug described in misc/clang_aliasing.c. - */ - -#undef DUK_USE_SELF_TESTS -#if defined(DUK_OPT_SELF_TESTS) -#define DUK_USE_SELF_TESTS +#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 -/* Double aliasing testcase fails when Emscripten-generated code is run - * on Firefox. This is not fatal because it only affects packed duk_tval - * which we avoid with Emscripten. - */ -#undef DUK_USE_NO_DOUBLE_ALIASING_SELFTEST -#if defined(DUK_F_EMSCRIPTEN) -#define DUK_USE_NO_DOUBLE_ALIASING_SELFTEST +#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 -/* - * Codecs - */ - -#define DUK_USE_JX -#if defined(DUK_OPT_NO_JX) -#undef DUK_USE_JX +#if defined(DUK_OPT_REFCOUNT16) +#define DUK_USE_REFCOUNT16 +#elif defined(DUK_OPT_NO_REFCOUNT16) +#undef DUK_USE_REFCOUNT16 +#else +#undef DUK_USE_REFCOUNT16 #endif -#define DUK_USE_JC -#if defined(DUK_OPT_NO_JC) -#undef DUK_USE_JC +#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 -/* - * InitJS code - */ - -/* Always use the built-in InitJS code for now. */ -#define DUK_USE_BUILTIN_INITJS - -/* User provided InitJS. */ -#undef DUK_USE_USER_INITJS -#if defined(DUK_OPT_USER_INITJS) -#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS) +#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 +#undef DUK_USE_REGEXP_CANON_WORKAROUND #endif -/* - * External string data support - * - * Allow duk_hstrings to store data also behind an external pointer (see - * duk_hstring_external). This increases code size slightly but is useful - * in low memory environments where memory is more limited than flash. - */ - -#undef DUK_USE_HSTRING_EXTDATA -#if defined(DUK_OPT_EXTERNAL_STRINGS) -#define DUK_USE_HSTRING_EXTDATA +#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_SUPPORT #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)) +#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 -#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)) +#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 -/* - * Lightweight functions - */ - -/* Force built-ins to use lightfunc function pointers when possible. This - * makes the built-in functions non-compliant with respect to their property - * values and such, but is very useful in low memory environments (can save - * around 14kB of initial RAM footprint). - */ -#undef DUK_USE_LIGHTFUNC_BUILTINS -#if defined(DUK_OPT_LIGHTFUNC_BUILTINS) -#define DUK_USE_LIGHTFUNC_BUILTINS +#if defined(DUK_OPT_SETJMP) +#define DUK_USE_SETJMP +#elif defined(DUK_OPT_NO_SETJMP) +#undef DUK_USE_SETJMP +#else +#define DUK_USE_SETJMP #endif -/* - * Pointer compression and 16-bit header fields for low memory environments - */ +#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 -#undef DUK_USE_HEAPPTR16 -#undef DUK_USE_HEAPPTR_ENC16 -#undef DUK_USE_HEAPPTR_DEC16 -#if defined(DUK_OPT_HEAPPTR16) && defined(DUK_OPT_HEAPPTR_ENC16) && defined(DUK_OPT_HEAPPTR_DEC16) -#define DUK_USE_HEAPPTR16 -#define DUK_USE_HEAPPTR_ENC16(udata,ptr) DUK_OPT_HEAPPTR_ENC16((udata),(ptr)) -#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr)) +#if defined(DUK_OPT_SIGSETJMP) +#define DUK_USE_SIGSETJMP +#elif defined(DUK_OPT_NO_SIGSETJMP) +#undef DUK_USE_SIGSETJMP +#else +#undef DUK_USE_SIGSETJMP #endif -#undef DUK_USE_DATAPTR16 -#undef DUK_USE_DATAPTR_ENC16 -#undef DUK_USE_DATAPTR_DEC16 -#if defined(DUK_OPT_DATAPTR16) && defined(DUK_OPT_DATAPTR_ENC16) && defined(DUK_OPT_DATAPTR_DEC16) -#define DUK_USE_DATAPTR16 -#define DUK_USE_DATAPTR_ENC16(udata,ptr) DUK_OPT_DATAPTR_ENC16((udata),(ptr)) -#define DUK_USE_DATAPTR_DEC16(udata,ptr) DUK_OPT_DATAPTR_DEC16((udata),(ptr)) +#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 -#undef DUK_USE_FUNCPTR16 -#undef DUK_USE_FUNCPTR_ENC16 -#undef DUK_USE_FUNCPTR_DEC16 -#if defined(DUK_OPT_FUNCPTR16) && defined(DUK_OPT_FUNCPTR_ENC16) && defined(DUK_OPT_FUNCPTR_DEC16) -#define DUK_USE_FUNCPTR16 -#define DUK_USE_FUNCPTR_ENC16(udata,ptr) DUK_OPT_FUNCPTR_ENC16((udata),(ptr)) -#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr)) +#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 -#undef DUK_USE_REFCOUNT16 -#if defined(DUK_OPT_REFCOUNT16) -#define DUK_USE_REFCOUNT16 +#if defined(DUK_OPT_STRICT_DECL) +#define DUK_USE_STRICT_DECL +#elif defined(DUK_OPT_NO_STRICT_DECL) +#undef DUK_USE_STRICT_DECL +#else +#define DUK_USE_STRICT_DECL #endif -#undef DUK_USE_STRHASH16 -#if defined(DUK_OPT_STRHASH16) -#define DUK_USE_STRHASH16 +#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 -#undef DUK_USE_STRLEN16 #if defined(DUK_OPT_STRLEN16) #define DUK_USE_STRLEN16 +#elif defined(DUK_OPT_NO_STRLEN16) +#undef DUK_USE_STRLEN16 +#else +#undef DUK_USE_STRLEN16 #endif -#undef DUK_USE_BUFLEN16 -#if defined(DUK_OPT_BUFLEN16) -#define DUK_USE_BUFLEN16 +#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_OBJSIZES16 -#if defined(DUK_OPT_OBJSIZES16) -#define DUK_USE_OBJSIZES16 +#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 -/* For now, hash part is dropped if and only if 16-bit object fields are used. */ -#define DUK_USE_HOBJECT_HASH_PART -#if defined(DUK_USE_OBJSIZES16) -#undef DUK_USE_HOBJECT_HASH_PART +#undef DUK_USE_STRTAB_PROBE +#if !(defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)) +#define DUK_USE_STRTAB_PROBE #endif -/* - * Miscellaneous - */ - -/* Convenience define: 32-bit pointers. 32-bit platforms are an important - * footprint optimization target, and this define allows e.g. struct sizes - * to be organized for compactness. - */ -#undef DUK_USE_32BIT_PTRS -#if defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) -#if DUK_UINTPTR_MAX <= 0xffffffffUL -#define DUK_USE_32BIT_PTRS -#endif +#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY) +#undef DUK_USE_TAILCALL +#else +#define DUK_USE_TAILCALL #endif -#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS -#undef DUK_USE_EXPLICIT_NULL_INIT - -#define DUK_USE_ZERO_BUFFER_DATA -#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA) -#undef DUK_USE_ZERO_BUFFER_DATA +#if defined(DUK_OPT_TARGET_INFO) +#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO +#else +#define DUK_USE_TARGET_INFO "unknown" #endif -#undef DUK_USE_VARIADIC_MACROS -#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) -#define DUK_USE_VARIADIC_MACROS -#endif -#if defined(_MSC_VER) && !defined(DUK_USE_VARIADIC_MACROS) -#if (_MSC_VER >= 1400) -/* VS2005+ should have variadic macros even when they're not C99. */ -#define DUK_USE_VARIADIC_MACROS +#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 -/* - * Variable size array initialization. - * - * Variable size array at the end of a structure is nonportable. - * There are three alternatives: - * - * 1) C99 (flexible array member): char buf[] - * 2) Compiler specific (e.g. GCC): char buf[0] - * 3) Portable but wastes memory / complicates allocation: char buf[1] - */ +#if defined(DUK_OPT_UNDERSCORE_SETJMP) +#define DUK_USE_UNDERSCORE_SETJMP +#elif defined(DUK_OPT_NO_UNDERSCORE_SETJMP) +#undef DUK_USE_UNDERSCORE_SETJMP +#else +#undef DUK_USE_UNDERSCORE_SETJMP +#endif -/* XXX: Currently unused, only hbuffer.h needed this at some point. */ -#undef DUK_USE_FLEX_C99 -#undef DUK_USE_FLEX_ZEROSIZE -#undef DUK_USE_FLEX_ONESIZE -#if defined(DUK_F_C99) -#define DUK_USE_FLEX_C99 -#elif defined(__GNUC__) -#define DUK_USE_FLEX_ZEROSIZE +#if defined(DUK_OPT_DECLARE) +#define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE #else -#define DUK_USE_FLEX_ONESIZE +#define DUK_USE_USER_DECLARE() /* no user declarations */ #endif -/* - * GCC pragmas - */ +/* User provided InitJS. */ +#undef DUK_USE_USER_INITJS +#if defined(DUK_OPT_USER_INITJS) +#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS) +#endif -/* XXX: GCC pragma inside a function fails in some earlier GCC versions (e.g. gcc 4.5). - * This is very approximate but allows clean builds for development right now. - */ -/* http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html */ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6) -#define DUK_USE_GCC_PRAGMAS +#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_GCC_PRAGMAS +#define DUK_USE_VERBOSE_ERRORS #endif -/* - * User declarations - */ +#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_VOLUNTARY_GC +#endif -#if defined(DUK_OPT_DECLARE) -#define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE +#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_USER_DECLARE() /* no user declarations */ +#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_INTEGER_ME +#undef DUK_USE_EXPLICIT_NULL_INIT +#define DUK_USE_FAST_REFCOUNT_DEFAULT +#define DUK_USE_HEX_FASTPATH #undef DUK_USE_INTERRUPT_DEBUG_FIXUP #define DUK_USE_JSON_DECNUMBER_FASTPATH #define DUK_USE_JSON_DECSTRING_FASTPATH @@ -3044,12 +3373,21 @@ typedef FILE duk_file; #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 +#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 @@ -3084,13 +3422,10 @@ typedef FILE duk_file; #if defined(DUK_USE_DATE_GET_NOW) /* External provider already defined. */ #elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx); #define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx)) #elif defined(DUK_USE_DATE_NOW_TIME) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx); #define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx)) #elif defined(DUK_USE_DATE_NOW_WINDOWS) -DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx); #define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx)) #else #error no provider for DUK_USE_DATE_GET_NOW() @@ -3099,10 +3434,8 @@ DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx); #if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) /* External provider already defined. */ #elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) -DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d); #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) #elif defined(DUK_USE_DATE_TZO_WINDOWS) -DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d); #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) #else #error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() @@ -3111,10 +3444,8 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t #if defined(DUK_USE_DATE_PARSE_STRING) /* External provider already defined. */ #elif defined(DUK_USE_DATE_PRS_STRPTIME) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str); #define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str)) #elif defined(DUK_USE_DATE_PRS_GETDATE) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str); #define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str)) #else /* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */ @@ -3123,7 +3454,6 @@ DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, #if defined(DUK_USE_DATE_FORMAT_STRING) /* External provider already defined. */ #elif defined(DUK_USE_DATE_FMT_STRFTIME) -DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags); #define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \ duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags)) #else @@ -3133,109 +3463,183 @@ DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, #endif /* DUK_COMPILING_DUKTAPE */ /* - * Sanity check for the final effective internal defines. Also - * double checks user tweaks made by an optional duk_custom.h header. - */ - -/* - * Deprecated feature options. - * - * Catch so that user more easily notices and updates build. + * Checks for config option consistency (DUK_USE_xxx) */ -#if defined(DUK_OPT_NO_FUNC_STMT) -#error DUK_OPT_NO_FUNC_STMT is deprecated, use DUK_OPT_NO_NONSTD_FUNC_STMT +#if defined(DUK_USE_32BIT_PTRS) +#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS #endif - -#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY) -#error DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY is deprecated, use DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY +#if defined(DUK_USE_ALIGN_4) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4 #endif - -#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY) -#error DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY is deprecated, use DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY +#if defined(DUK_USE_ALIGN_8) +#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8 #endif - -#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT) -#error DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT is deprecated, use DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT +#if defined(DUK_USE_BYTEORDER_FORCED) +#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED #endif - -#if defined(DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY) -#error DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY is deprecated, use DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY +#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_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF) -#error DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF is deprecated, use DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF +#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_OPT_NO_JSONX) -#error DUK_OPT_NO_JSONX is deprecated, use DUK_OPT_NO_JX +#if defined(DUK_USE_DEBUGGER_DUMPHEAP) && !defined(DUK_USE_DEBUGGER_SUPPORT) +#error config option DUK_USE_DEBUGGER_DUMPHEAP requires option DUK_USE_DEBUGGER_SUPPORT (which is missing) #endif - -#if defined(DUK_OPT_NO_JSONC) -#error DUK_OPT_NO_JSONC is deprecated, use DUK_OPT_NO_JC +#if defined(DUK_USE_DEBUGGER_FWD_LOGGING) && !defined(DUK_USE_DEBUGGER_SUPPORT) +#error config option DUK_USE_DEBUGGER_FWD_LOGGING requires option DUK_USE_DEBUGGER_SUPPORT (which is missing) +#endif +#if defined(DUK_USE_DEBUGGER_FWD_PRINTALERT) && !defined(DUK_USE_DEBUGGER_SUPPORT) +#error config option DUK_USE_DEBUGGER_FWD_PRINTALERT requires option DUK_USE_DEBUGGER_SUPPORT (which is missing) +#endif +#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) && !defined(DUK_USE_DEBUGGER_SUPPORT) +#error config option DUK_USE_DEBUGGER_PAUSE_UNCAUGHT requires option DUK_USE_DEBUGGER_SUPPORT (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_DEBUGGER_THROW_NOTIFY) && !defined(DUK_USE_DEBUGGER_SUPPORT) +#error config option DUK_USE_DEBUGGER_THROW_NOTIFY requires option DUK_USE_DEBUGGER_SUPPORT (which is missing) +#endif +#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE) && !defined(DUK_USE_DEBUGGER_SUPPORT) +#error config option DUK_USE_DEBUGGER_TRANSPORT_TORTURE requires option DUK_USE_DEBUGGER_SUPPORT (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 - -/* - * Debug print consistency - */ - #if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG) -#error DUK_USE_DPRINT without DUK_USE_DEBUG +#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing) #endif - -#if defined(DUK_USE_DDPRINT) && !defined(DUK_USE_DEBUG) -#error DUK_USE_DDPRINT without DUK_USE_DEBUG +#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_DDDPRINT) && !defined(DUK_USE_DEBUG) -#error DUK_USE_DDDPRINT without DUK_USE_DEBUG +#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) -/* Debug code doesn't have access to 'heap' so it cannot decode pointers. */ -#error debug printing cannot currently be used with heap pointer compression +#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined) #endif - -/* - * Debugger consistency - */ - -#if defined(DUK_USE_DEBUGGER_SUPPORT) -#if !defined(DUK_USE_INTERRUPT_COUNTER) -#error DUK_USE_INTERRUPT_COUNTER is needed when debugger support is enabled +#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_PC2LINE) -#error DUK_USE_PC2LINE is needed when debugger support is enabled +#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 - -/* - * Garbage collection consistency - */ - -#if defined(DUK_USE_REFERENCE_COUNTING) && !defined(DUK_USE_DOUBLE_LINKED_HEAP) -#error DUK_USE_REFERENCE_COUNTING defined without DUK_USE_DOUBLE_LINKED_HEAP +#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_GC_TORTURE) && !defined(DUK_USE_MARK_AND_SWEEP) -#error DUK_USE_GC_TORTURE defined without DUK_USE_MARK_AND_SWEEP +#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 - -/* - * Low memory feature consistency - */ - -#if defined(DUK_USE_OBJSIZES16) -#if defined(DUK_USE_HOBJECT_HASH_PART) -#error DUK_USE_OBJSIZES16 assumes DUK_USE_HOBJECT_HASH_PART is not defined +#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_STRTAB_CHAIN) && defined(DUK_USE_STRTAB_PROBE) -#error both DUK_USE_STRTAB_CHAIN and DUK_USE_STRTAB_PROBE defined +#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_STRTAB_CHAIN) && !defined(DUK_USE_STRTAB_PROBE) -#error neither DUK_USE_STRTAB_CHAIN nor DUK_USE_STRTAB_PROBE is defined +#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 + +/* + * Convert DUK_USE_BYTEORDER, from whatever source, into currently used + * internal defines. If detection failed, #error out. + */ + +#if defined(DUK_USE_BYTEORDER) +#if (DUK_USE_BYTEORDER == 1) +#define DUK_USE_INTEGER_LE +#define DUK_USE_DOUBLE_LE +#elif (DUK_USE_BYTEORDER == 2) +#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ +#define DUK_USE_DOUBLE_ME +#elif (DUK_USE_BYTEORDER == 3) +#define DUK_USE_INTEGER_BE +#define DUK_USE_DOUBLE_BE +#else +#error unsupported: byte order invalid +#endif /* byte order */ +#else +#error unsupported: byte order detection failed +#endif /* defined(DUK_USE_BYTEORDER) */ #endif /* DUK_CONFIG_H_INCLUDED */ diff --git a/javascript/duktape/duktape.c b/javascript/duktape/duktape.c index 530a27aea..184767de4 100644 --- a/javascript/duktape/duktape.c +++ b/javascript/duktape/duktape.c @@ -1,10 +1,8 @@ -// Omit from static analysis. -#ifndef __clang_analyzer__ /* * Single source autogenerated distributable for Duktape 1.3.99. - * Git commit 40453939c5a5aa16898d19bbac4d02f77196cc8b (v1.3.0-138-g4045393). - * Git branch regexp-canonicalize-lookup. + * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f). + * Git branch duk-config-improvements. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -158,23 +156,31 @@ DUK_USE_USER_DECLARE() #ifndef DUK_REPLACEMENTS_H_INCLUDED #define DUK_REPLACEMENTS_H_INCLUDED -#ifdef DUK_USE_REPL_FPCLASSIFY +#if defined(DUK_USE_COMPUTED_INFINITY) +DUK_INTERNAL_DECL double duk_computed_infinity; +#endif + +#if defined(DUK_USE_COMPUTED_NAN) +DUK_INTERNAL_DECL double duk_computed_nan; +#endif + +#if defined(DUK_USE_REPL_FPCLASSIFY) DUK_INTERNAL_DECL int duk_repl_fpclassify(double x); #endif -#ifdef DUK_USE_REPL_SIGNBIT +#if defined(DUK_USE_REPL_SIGNBIT) DUK_INTERNAL_DECL int duk_repl_signbit(double x); #endif -#ifdef DUK_USE_REPL_ISFINITE +#if defined(DUK_USE_REPL_ISFINITE) DUK_INTERNAL_DECL int duk_repl_isfinite(double x); #endif -#ifdef DUK_USE_REPL_ISNAN +#if defined(DUK_USE_REPL_ISNAN) DUK_INTERNAL_DECL int duk_repl_isnan(double x); #endif -#ifdef DUK_USE_REPL_ISINF +#if defined(DUK_USE_REPL_ISINF) DUK_INTERNAL_DECL int duk_repl_isinf(double x); #endif @@ -727,11 +733,11 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_STRIDX_TRY 389 /* 'try' */ #define DUK_STRIDX_TYPEOF 390 /* 'typeof' */ #define DUK_STRIDX_VAR 391 /* 'var' */ -#define DUK_STRIDX_VOID 392 /* 'void' */ -#define DUK_STRIDX_WHILE 393 /* 'while' */ -#define DUK_STRIDX_WITH 394 /* 'with' */ -#define DUK_STRIDX_CLASS 395 /* 'class' */ -#define DUK_STRIDX_CONST 396 /* 'const' */ +#define DUK_STRIDX_CONST 392 /* 'const' */ +#define DUK_STRIDX_VOID 393 /* 'void' */ +#define DUK_STRIDX_WHILE 394 /* 'while' */ +#define DUK_STRIDX_WITH 395 /* 'with' */ +#define DUK_STRIDX_CLASS 396 /* 'class' */ #define DUK_STRIDX_ENUM 397 /* 'enum' */ #define DUK_STRIDX_EXPORT 398 /* 'export' */ #define DUK_STRIDX_EXTENDS 399 /* 'extends' */ @@ -1534,6 +1540,8 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) #define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR) #define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR) +#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) +#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) #define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID) #define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID) #define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) @@ -1542,8 +1550,6 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) #define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS) #define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS) -#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) -#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) #define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM) #define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM) #define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) @@ -1586,16 +1592,16 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_STRIDX_END_RESERVED 414 /* exclusive endpoint */ #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[147]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149]; DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952]; #ifdef DUK_USE_BUILTIN_INITJS -DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[1757]; +DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187]; #endif /* DUK_USE_BUILTIN_INITJS */ #endif /* !DUK_SINGLE_FILE */ #define DUK_BUILTINS_DATA_LENGTH 1952 #ifdef DUK_USE_BUILTIN_INITJS -#define DUK_BUILTIN_INITJS_DATA_LENGTH 1757 +#define DUK_BUILTIN_INITJS_DATA_LENGTH 187 #endif /* DUK_USE_BUILTIN_INITJS */ #define DUK_BIDX_GLOBAL 0 @@ -2072,11 +2078,11 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_STRIDX_TRY 389 /* 'try' */ #define DUK_STRIDX_TYPEOF 390 /* 'typeof' */ #define DUK_STRIDX_VAR 391 /* 'var' */ -#define DUK_STRIDX_VOID 392 /* 'void' */ -#define DUK_STRIDX_WHILE 393 /* 'while' */ -#define DUK_STRIDX_WITH 394 /* 'with' */ -#define DUK_STRIDX_CLASS 395 /* 'class' */ -#define DUK_STRIDX_CONST 396 /* 'const' */ +#define DUK_STRIDX_CONST 392 /* 'const' */ +#define DUK_STRIDX_VOID 393 /* 'void' */ +#define DUK_STRIDX_WHILE 394 /* 'while' */ +#define DUK_STRIDX_WITH 395 /* 'with' */ +#define DUK_STRIDX_CLASS 396 /* 'class' */ #define DUK_STRIDX_ENUM 397 /* 'enum' */ #define DUK_STRIDX_EXPORT 398 /* 'export' */ #define DUK_STRIDX_EXTENDS 399 /* 'extends' */ @@ -2879,6 +2885,8 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) #define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR) #define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR) +#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) +#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) #define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID) #define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID) #define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) @@ -2887,8 +2895,6 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) #define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS) #define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS) -#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) -#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) #define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM) #define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM) #define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) @@ -2931,16 +2937,16 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_STRIDX_END_RESERVED 414 /* exclusive endpoint */ #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[147]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149]; DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952]; #ifdef DUK_USE_BUILTIN_INITJS -DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[1757]; +DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187]; #endif /* DUK_USE_BUILTIN_INITJS */ #endif /* !DUK_SINGLE_FILE */ #define DUK_BUILTINS_DATA_LENGTH 1952 #ifdef DUK_USE_BUILTIN_INITJS -#define DUK_BUILTIN_INITJS_DATA_LENGTH 1757 +#define DUK_BUILTIN_INITJS_DATA_LENGTH 187 #endif /* DUK_USE_BUILTIN_INITJS */ #define DUK_BIDX_GLOBAL 0 @@ -3417,11 +3423,11 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_STRIDX_TRY 389 /* 'try' */ #define DUK_STRIDX_TYPEOF 390 /* 'typeof' */ #define DUK_STRIDX_VAR 391 /* 'var' */ -#define DUK_STRIDX_VOID 392 /* 'void' */ -#define DUK_STRIDX_WHILE 393 /* 'while' */ -#define DUK_STRIDX_WITH 394 /* 'with' */ -#define DUK_STRIDX_CLASS 395 /* 'class' */ -#define DUK_STRIDX_CONST 396 /* 'const' */ +#define DUK_STRIDX_CONST 392 /* 'const' */ +#define DUK_STRIDX_VOID 393 /* 'void' */ +#define DUK_STRIDX_WHILE 394 /* 'while' */ +#define DUK_STRIDX_WITH 395 /* 'with' */ +#define DUK_STRIDX_CLASS 396 /* 'class' */ #define DUK_STRIDX_ENUM 397 /* 'enum' */ #define DUK_STRIDX_EXPORT 398 /* 'export' */ #define DUK_STRIDX_EXTENDS 399 /* 'extends' */ @@ -4224,6 +4230,8 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) #define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR) #define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR) +#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) +#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) #define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID) #define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID) #define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) @@ -4232,8 +4240,6 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) #define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS) #define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS) -#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) -#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) #define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM) #define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM) #define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) @@ -4276,16 +4282,16 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624]; #define DUK_STRIDX_END_RESERVED 414 /* exclusive endpoint */ #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[147]; +DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149]; DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952]; #ifdef DUK_USE_BUILTIN_INITJS -DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[1757]; +DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187]; #endif /* DUK_USE_BUILTIN_INITJS */ #endif /* !DUK_SINGLE_FILE */ #define DUK_BUILTINS_DATA_LENGTH 1952 #ifdef DUK_USE_BUILTIN_INITJS -#define DUK_BUILTIN_INITJS_DATA_LENGTH 1757 +#define DUK_BUILTIN_INITJS_DATA_LENGTH 187 #endif /* DUK_USE_BUILTIN_INITJS */ #define DUK_BIDX_GLOBAL 0 @@ -4834,9 +4840,17 @@ struct duk_bufwriter_ctx { */ #if !defined(DUK_SINGLE_FILE) -DUK_INTERNAL_DECL duk_uint8_t duk_lc_digits[36]; -DUK_INTERNAL_DECL duk_uint8_t duk_uc_nybbles[16]; -DUK_INTERNAL_DECL duk_int8_t duk_hex_dectab[256]; +DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36]; +DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16]; +DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256]; +#if defined(DUK_USE_HEX_FASTPATH) +DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256]; +DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256]; +#endif +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64]; +DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256]; +#endif #endif /* !DUK_SINGLE_FILE */ /* Note: assumes that duk_util_probe_steps size is 32 */ @@ -4846,7 +4860,9 @@ DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; #endif /* !DUK_SINGLE_FILE */ #endif +#if defined(DUK_USE_STRHASH_DENSE) DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); +#endif #if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE) DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size); @@ -4934,20 +4950,23 @@ DUK_INTERNAL_DECL const char *duk_str_not_configurable; #endif /* !DUK_SINGLE_FILE */ #define DUK_STR_INVALID_CONTEXT duk_str_invalid_context -#define DUK_STR_INVALID_INDEX duk_str_invalid_index +#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args #define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack -#define DUK_STR_NOT_UNDEFINED duk_str_not_undefined -#define DUK_STR_NOT_NULL duk_str_not_null -#define DUK_STR_NOT_BOOLEAN duk_str_not_boolean -#define DUK_STR_NOT_NUMBER duk_str_not_number -#define DUK_STR_NOT_STRING duk_str_not_string -#define DUK_STR_NOT_POINTER duk_str_not_pointer -#define DUK_STR_NOT_BUFFER duk_str_not_buffer +#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type +#define DUK_STR_NOT_NULL duk_str_unexpected_type +#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type +#define DUK_STR_NOT_NUMBER duk_str_unexpected_type +#define DUK_STR_NOT_STRING duk_str_unexpected_type +#define DUK_STR_NOT_OBJECT duk_str_unexpected_type +#define DUK_STR_NOT_POINTER duk_str_unexpected_type +#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */ #define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type -#define DUK_STR_NOT_THREAD duk_str_not_thread -#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_not_compiledfunction -#define DUK_STR_NOT_NATIVEFUNCTION duk_str_not_nativefunction -#define DUK_STR_NOT_C_FUNCTION duk_str_not_c_function +#define DUK_STR_NOT_THREAD duk_str_unexpected_type +#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type +#define DUK_STR_NOT_REGEXP duk_str_unexpected_type #define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed #define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range #define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible @@ -4968,20 +4987,9 @@ DUK_INTERNAL_DECL const char *duk_str_not_configurable; #if !defined(DUK_SINGLE_FILE) DUK_INTERNAL_DECL const char *duk_str_invalid_context; -DUK_INTERNAL_DECL const char *duk_str_invalid_index; DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack; -DUK_INTERNAL_DECL const char *duk_str_not_undefined; -DUK_INTERNAL_DECL const char *duk_str_not_null; -DUK_INTERNAL_DECL const char *duk_str_not_boolean; -DUK_INTERNAL_DECL const char *duk_str_not_number; -DUK_INTERNAL_DECL const char *duk_str_not_string; -DUK_INTERNAL_DECL const char *duk_str_not_pointer; DUK_INTERNAL_DECL const char *duk_str_not_buffer; DUK_INTERNAL_DECL const char *duk_str_unexpected_type; -DUK_INTERNAL_DECL const char *duk_str_not_thread; -DUK_INTERNAL_DECL const char *duk_str_not_compiledfunction; -DUK_INTERNAL_DECL const char *duk_str_not_nativefunction; -DUK_INTERNAL_DECL const char *duk_str_not_c_function; DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed; DUK_INTERNAL_DECL const char *duk_str_number_outside_range; DUK_INTERNAL_DECL const char *duk_str_not_object_coercible; @@ -5453,13 +5461,13 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo #define DUK_TOK_TRY 22 #define DUK_TOK_TYPEOF 23 #define DUK_TOK_VAR 24 -#define DUK_TOK_VOID 25 -#define DUK_TOK_WHILE 26 -#define DUK_TOK_WITH 27 +#define DUK_TOK_CONST 25 +#define DUK_TOK_VOID 26 +#define DUK_TOK_WHILE 27 +#define DUK_TOK_WITH 28 /* reserved words: future reserved words */ -#define DUK_TOK_CLASS 28 -#define DUK_TOK_CONST 29 +#define DUK_TOK_CLASS 29 #define DUK_TOK_ENUM 30 #define DUK_TOK_EXPORT 31 #define DUK_TOK_EXTENDS 32 @@ -6158,11 +6166,6 @@ DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hack * Packed 8-byte representation */ -/* sanity */ -#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) -#error packed representation not supported -#endif - /* use duk_double_union as duk_tval directly */ typedef union duk_double_union duk_tval; @@ -7108,13 +7111,13 @@ struct duk_heaphdr_string { } while (0) /* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, - * etc, so it's very important for performance. + * etc, so it's very important for performance. Measure when changing. * * NOTE: the source and destination duk_tval pointers may be the same, and * the macros MUST deal with that correctly. */ -/* Original idiom used. */ +/* Original idiom used, minimal code size. */ #define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ @@ -7124,83 +7127,22 @@ struct duk_heaphdr_string { DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ } while (0) -#if 0 /* XXX: to optimize and measure */ -/* Original idiom but with forced fast refcount macros. */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT0F(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF_FAST((thr), tv__src); \ - DUK_TVAL_DECREF_FAST((thr), &tv__tmp); /* side effects */ \ - } while (0) - -/* Use 'h__obj' temporary to avoid a full duk_tval copy. */ +/* Faster alternative: avoid making a temporary copy of tvptr_dst and use + * fast incref/decref macros. + */ #define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - if (DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst)) { \ - h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ - DUK_ASSERT(h__obj != NULL); \ - } else { \ - h__obj = NULL; \ - } \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF((thr), tv__src); \ - if (h__obj != NULL) { \ - DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ - } \ - } while (0) - -/* Use 'h__obj' temporary to avoid a full duk_tval copy. */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT1A(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - if (DUK_UNLIKELY(DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst))) { \ - h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ - DUK_ASSERT(h__obj != NULL); \ - } else { \ - h__obj = NULL; \ - } \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ DUK_TVAL_INCREF_FAST((thr), tv__src); \ - if (DUK_UNLIKELY(h__obj != NULL)) { \ - DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ - } \ - } while (0) - -/* Avoid rechecking 'h__obj'. */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT2(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ if (DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst)) { \ h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ DUK_ASSERT(h__obj != NULL); \ DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF((thr), tv__src); \ - DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ - } else { \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF((thr), tv__src); \ - } \ - } while (0) - -/* Avoid rechecking 'h__obj'. */ -#define DUK_TVAL_SET_TVAL_UPDREF_ALT3(thr,tvptr_dst,tvptr_src) do { \ - duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ - tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ - if (DUK_UNLIKELY(DUK_TVAL_IS_HEAP_ALLOCATED(tv__dst))) { \ - h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ - DUK_ASSERT(h__obj != NULL); \ - DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF_FAST((thr), tv__src); \ DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ } else { \ DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ - DUK_TVAL_INCREF_FAST((thr), tv__src); \ } \ } while (0) -#endif /* XXX: no optimized variants yet */ #define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 @@ -7224,8 +7166,8 @@ struct duk_heaphdr_string { #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) /* Optimized for speed. */ -#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 -#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 +#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 +#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 #define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 #else /* Optimized for size. */ @@ -7421,6 +7363,10 @@ duk_bool_t duk_valstack_resize_raw(duk_context *ctx, duk_size_t min_new_size, duk_small_uint_t flags); +#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index); +#endif + DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index); DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index); DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv); @@ -7462,13 +7408,6 @@ DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx); #define duk_push_size_t(ctx,val) \ duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */ -/* internal helper for looking up a tagged type */ -#define DUK_GETTAGGED_FLAG_ALLOW_NULL (1L << 24) -#define DUK_GETTAGGED_FLAG_CHECK_CLASS (1L << 25) -#define DUK_GETTAGGED_CLASS_SHIFT 16 - -DUK_INTERNAL_DECL duk_heaphdr *duk_get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t flags_and_tag); - DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index); DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index); DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index); @@ -7476,10 +7415,7 @@ DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index); DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index); -#define duk_get_hobject_with_class(ctx,index,classnum) \ - ((duk_hobject *) duk_get_tagged_heaphdr_raw((ctx), (index), \ - DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL | \ - DUK_GETTAGGED_FLAG_CHECK_CLASS | ((classnum) << DUK_GETTAGGED_CLASS_SHIFT))) +DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum); #if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */ DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index); @@ -7494,6 +7430,10 @@ DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) #if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index); #endif +DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx); +#if !defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h); +#endif DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */ DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval); @@ -7509,10 +7449,7 @@ DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t i DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index); DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index); -#define duk_require_hobject_with_class(ctx,index,classnum) \ - ((duk_hobject *) duk_get_tagged_heaphdr_raw((ctx), (index), \ - DUK_TAG_OBJECT | \ - DUK_GETTAGGED_FLAG_CHECK_CLASS | ((classnum) << DUK_GETTAGGED_CLASS_SHIFT))) +DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum); DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index); DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index); @@ -7540,6 +7477,11 @@ DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv); DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv); DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); +#if !defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index); +DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv); +#endif + DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */ DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */ DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */ @@ -9806,6 +9748,7 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ #define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ #define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ +#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ #define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits)) #define DUK__HEAP_SET_FLAGS(heap,bits) do { \ @@ -9820,18 +9763,21 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) +#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) #define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) #define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) +#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) #define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) #define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) #define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) #define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) +#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) /* * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally') @@ -9856,8 +9802,9 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic * #define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ #define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ -#define DUK_MS_FLAG_NO_FINALIZERS (1 << 2) /* don't run finalizers (which may have arbitrary side effects) */ -#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 3) /* don't compact objects; needed during object property allocation resize */ +#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ +#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ +#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ /* * Thread switching @@ -10221,6 +10168,7 @@ struct duk_heap { duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */ duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */ duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */ + duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */ duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */ duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */ duk_size_t dbg_step_csindex; /* callstack index */ @@ -10234,6 +10182,10 @@ struct duk_heap { duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */ duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */ duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */ + + /* Used to support single-byte stream lookahead. */ + duk_bool_t dbg_have_next_byte; + duk_uint8_t dbg_next_byte; #endif /* string intern table (weak refs) */ @@ -10383,6 +10335,7 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin #define DUK_DBG_CMD_ALERT 0x03 #define DUK_DBG_CMD_LOG 0x04 #define DUK_DBG_CMD_THROW 0x05 +#define DUK_DBG_CMD_DETACHING 0x06 /* Initiated by debug client */ #define DUK_DBG_CMD_BASICINFO 0x10 @@ -10433,7 +10386,7 @@ DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *dat DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h); DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length); DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h); -DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, const void *ptr); +DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr); #if defined(DUK_USE_DEBUGGER_DUMPHEAP) DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h); #endif @@ -10448,9 +10401,11 @@ DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uin DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command); DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr); -DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr); -DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr); +DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr); +DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr); +#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal); +#endif DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc); DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block); @@ -10636,7 +10591,7 @@ DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash; DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...); #endif /* DUK_USE_VARIADIC_MACROS */ -DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk_size_t length); +DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length); DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x); DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x); DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...); @@ -10694,9 +10649,9 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); * fall back to awkward hacks. */ -#ifdef DUK_USE_VERBOSE_ERRORS +#if defined(DUK_USE_VERBOSE_ERRORS) -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) /* __VA_ARGS__ has comma issues for empty lists, so we mandate at least 1 argument for '...' (format string) */ #define DUK_ERROR(thr,err,...) duk_err_handle_error(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (err), __VA_ARGS__) @@ -10718,7 +10673,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); #else /* DUK_USE_VERBOSE_ERRORS */ -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) #define DUK_ERROR(thr,err,...) duk_err_handle_error((thr), (err)) #define DUK_ERROR_RAW(file,line,thr,err,...) duk_err_handle_error((thr), (err)) @@ -10770,7 +10725,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); * Assert macro: failure causes panic. */ -#ifdef DUK_USE_ASSERTIONS +#if defined(DUK_USE_ASSERTIONS) /* the message should be a compile time constant without formatting (less risk); * we don't care about assertion text size because they're not used in production @@ -10861,12 +10816,55 @@ 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. + */ + +#if defined(DUK_USE_VERBOSE_ERRORS) +#if defined(DUK_USE_PARANOID_ERRORS) +/* Verbose but paranoid errors. */ + +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ + duk_err_require_type_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (index), (expectname)); \ + } while (0) +#else +/* Verbose errors with key/value summaries. */ + +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ + duk_err_require_type_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (index), (expectname)); \ + } while (0) +#endif +#define DUK_ERROR_API_INDEX(thr,index) do { \ + duk_err_api_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (index)); \ + } while (0) +#define DUK_ERROR_API(thr,msg) do { \ + duk_err_api(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (msg)); \ + } while (0) +#else +/* Non-verbose errors for low memory targets. */ + +#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \ + duk_err_require_type_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (lowmemstr)); \ + } while (0) +#define DUK_ERROR_API_INDEX(thr,index) do { \ + duk_err_api_index(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr)); \ + } while (0) +#define DUK_ERROR_API(thr,msg) do { \ + duk_err_api(DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (thr), (msg)); \ + } while (0) +#endif + /* * Prototypes */ -#ifdef DUK_USE_VERBOSE_ERRORS -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VERBOSE_ERRORS) +#if defined(DUK_USE_VARIADIC_MACROS) DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(const char *filename, duk_int_t line, duk_hthread *thr, duk_errcode_t code, const char *fmt, ...)); #else /* DUK_USE_VARIADIC_MACROS */ #if !defined(DUK_SINGLE_FILE) @@ -10877,7 +10875,7 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(const char *filename, d DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_stash(duk_hthread *thr, duk_errcode_t code, const char *fmt, ...)); #endif /* DUK_USE_VARIADIC_MACROS */ #else /* DUK_USE_VERBOSE_ERRORS */ -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code)); #else /* DUK_USE_VARIADIC_MACROS */ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_nonverbose1(duk_hthread *thr, duk_errcode_t code, const char *fmt, ...)); @@ -10885,7 +10883,7 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_nonverbose2(const char #endif /* DUK_USE_VARIADIC_MACROS */ #endif /* DUK_USE_VERBOSE_ERRORS */ -#ifdef DUK_USE_VERBOSE_ERRORS +#if defined(DUK_USE_VERBOSE_ERRORS) DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line)); #else DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)); @@ -10900,6 +10898,20 @@ DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthrea DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr); #endif +#if defined(DUK_USE_VERBOSE_ERRORS) +#if defined(DUK_USE_PARANOID_ERRORS) +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name)); +#else +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name)); +#endif +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message)); +#else +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *error_msg)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr)); +DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message)); +#endif + DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr)); DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)); @@ -11134,12 +11146,13 @@ extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348]; extern const duk_uint8_t duk_unicode_caseconv_uc[1288]; extern const duk_uint8_t duk_unicode_caseconv_lc[616]; -/* FIXME: CONDITIONAL */ +#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) /* * Automatically generated by extract_caseconv.py, do not edit! */ extern const duk_uint16_t duk_unicode_re_canon_lookup[65536]; +#endif /* * Extern @@ -11199,10 +11212,8 @@ DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp) /* How much stack to require on entry to object/array decode */ #define DUK_JSON_DEC_REQSTACK 32 -/* How large a loop detection stack to use for fast path */ -#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +/* How large a loop detection stack to use */ #define DUK_JSON_ENC_LOOPARRAY 64 -#endif /* Encoding state. Heap object references are all borrowed. */ typedef struct { @@ -11210,7 +11221,6 @@ typedef struct { duk_bufwriter_ctx bw; /* output bufwriter */ duk_hobject *h_replacer; /* replacer function */ duk_hstring *h_gap; /* gap (if empty string, NULL) */ - duk_hstring *h_indent; /* current indent (if gap is NULL, this is NULL) */ duk_idx_t idx_proplist; /* explicit PropertyList */ duk_idx_t idx_loop; /* valstack index of loop detection object */ duk_small_uint_t flags; @@ -11219,6 +11229,7 @@ typedef struct { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) duk_small_uint_t flag_ext_custom; duk_small_uint_t flag_ext_compatible; + duk_small_uint_t flag_ext_custom_or_compatible; #endif duk_int_t recursion_depth; duk_int_t recursion_limit; @@ -11230,9 +11241,7 @@ typedef struct { duk_small_uint_t stridx_custom_posinf; duk_small_uint_t stridx_custom_function; #endif -#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */ -#endif } duk_json_enc_ctx; typedef struct { @@ -11245,6 +11254,7 @@ typedef struct { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) duk_small_uint_t flag_ext_custom; duk_small_uint_t flag_ext_compatible; + duk_small_uint_t flag_ext_custom_or_compatible; #endif duk_int_t recursion_depth; duk_int_t recursion_limit; @@ -11527,6 +11537,31 @@ DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year); DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x); DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year); DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x); +/* Built-in providers */ +#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) +DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx); +#endif +#if defined(DUK_USE_DATE_NOW_TIME) +DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx); +#endif +#if defined(DUK_USE_DATE_NOW_WINDOWS) +DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx); +#endif +#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME) +DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d); +#endif +#if defined(DUK_USE_DATE_TZO_WINDOWS) +DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d); +#endif +#if defined(DUK_USE_DATE_PRS_STRPTIME) +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str); +#endif +#if defined(DUK_USE_DATE_PRS_GETDATE) +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str); +#endif +#if defined(DUK_USE_DATE_FMT_STRFTIME) +DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags); +#endif DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx); @@ -11541,7 +11576,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx); -DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx); +DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx); DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx); @@ -11696,20 +11733,9 @@ DUK_INTERNAL const char *duk_str_not_writable = "not writable"; DUK_INTERNAL const char *duk_str_not_configurable = "not configurable"; DUK_INTERNAL const char *duk_str_invalid_context = "invalid context"; -DUK_INTERNAL const char *duk_str_invalid_index = "invalid index"; DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack"; -DUK_INTERNAL const char *duk_str_not_undefined = "not undefined"; -DUK_INTERNAL const char *duk_str_not_null = "not null"; -DUK_INTERNAL const char *duk_str_not_boolean = "not boolean"; -DUK_INTERNAL const char *duk_str_not_number = "not number"; -DUK_INTERNAL const char *duk_str_not_string = "not string"; -DUK_INTERNAL const char *duk_str_not_pointer = "not pointer"; -DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; +DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */ DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type"; -DUK_INTERNAL const char *duk_str_not_thread = "not thread"; -DUK_INTERNAL const char *duk_str_not_compiledfunction = "not compiledfunction"; -DUK_INTERNAL const char *duk_str_not_nativefunction = "not nativefunction"; -DUK_INTERNAL const char *duk_str_not_c_function = "not c function"; DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed"; DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range"; DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible"; @@ -11904,18 +11930,6 @@ DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE); duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); -#ifdef DUK_USE_DPRINT_RDTSC - DUK_FPRINTF(DUK_STDERR, "%s[%s] <%llu> %s:%ld (%s):%s %s%s\n", - (const char *) duk__get_term_1(level), - (const char *) duk__get_level_string(level), - (unsigned long long) DUK_USE_RDTSC(), /* match the inline asm in duk_features.h */ - (const char *) file, - (long) line, - (const char *) func, - (const char *) duk__get_term_2(level), - (const char *) duk__debug_buf, - (const char *) duk__get_term_3(level)); -#else DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n", (const char *) duk__get_term_1(level), (const char *) duk__get_level_string(level), @@ -11925,7 +11939,6 @@ DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int (const char *) duk__get_term_2(level), (const char *) duk__debug_buf, (const char *) duk__get_term_3(level)); -#endif DUK_FFLUSH(DUK_STDERR); va_end(ap); @@ -11947,18 +11960,6 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE); duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); -#ifdef DUK_USE_DPRINT_RDTSC - DUK_FPRINTF(DUK_STDERR, "%s[%s] <%llu> %s:%s (%s):%s %s%s\n", - (const char *) duk__get_term_1(level), - (const char *) duk__get_level_string(duk_debug_level_stash), - (unsigned long long) DUK_USE_RDTSC(), /* match duk_features.h */ - (const char *) duk_debug_file_stash, - (const char *) duk_debug_line_stash, - (const char *) duk_debug_func_stash, - (const char *) duk__get_term_2(level), - (const char *) duk__debug_buf, - (const char *) duk__get_term_3(level)); -#else DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n", (const char *) duk__get_term_1(level), (const char *) duk__get_level_string(duk_debug_level_stash), @@ -11968,7 +11969,6 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { (const char *) duk__get_term_2(level), (const char *) duk__debug_buf, (const char *) duk__get_term_3(level)); -#endif DUK_FFLUSH(DUK_STDERR); va_end(ap); @@ -12112,20 +12112,20 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[2624] = { 32,76,71,64,156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44, 147,32,134,226,17,114,33,202,134,129,107,192,202,232,160,180,104,166,135, 52,72,40,144,213,33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34, -98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,74,185,3,45, -142,133,144,150,68,206,81,44,18,145,68,230,202,100,35,104,195,18,239,116, -102,114,94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161, -10,80,46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222, -1,40,6,33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104, -17,112,130,44,96, +98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153, +42,228,12,182,58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114, +94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80, +46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6, +33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112, +130,44,96, }; /* to convert a heap stridx to a token number, subtract * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. */ -/* native functions: 147 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { +/* native functions: 149 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_array_constructor, duk_bi_array_constructor_is_array, duk_bi_array_prototype_concat, @@ -12173,9 +12173,11 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { duk_bi_duktape_object_info, duk_bi_error_constructor_shared, duk_bi_error_prototype_filename_getter, + duk_bi_error_prototype_filename_setter, duk_bi_error_prototype_linenumber_getter, - duk_bi_error_prototype_nop_setter, + duk_bi_error_prototype_linenumber_setter, duk_bi_error_prototype_stack_getter, + duk_bi_error_prototype_stack_setter, duk_bi_error_prototype_to_string, duk_bi_function_constructor, duk_bi_function_prototype, @@ -12276,38 +12278,38 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { }; DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { -105,195,75,16,121,40,105,51,14,252,104,52,8,131,72,0,115,225,65,165,236,55, -243,6,145,32,210,24,210,182,25,249,35,120,216,99,226,13,78,225,116,177,164, +105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55, +243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164, 180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96, 3,37,26,75,109,172,0,108,163,73,109,177,128,14,148,105,45,181,176,1,242, -144,56,209,32,94,6,167,101,98,80,211,24,1,250,67,72,168,67,232,13,46,128, -47,162,52,164,0,62,80,163,72,128,61,40,107,26,7,37,20,53,200,131,88,0,66, -134,185,16,98,80,215,34,11,96,0,138,26,228,65,76,0,69,67,92,136,37,128,6, -168,107,145,4,48,1,165,13,114,32,118,0,44,161,174,68,12,192,7,148,53,200, -129,88,1,26,134,165,48,130,80,31,255,241,69,224,0,0,0,0,0,0,124,63,174,32, +144,56,209,36,94,6,167,133,98,80,211,28,1,250,67,72,168,67,232,13,46,192, +47,162,52,165,0,62,80,163,72,128,61,40,107,26,7,37,20,53,201,131,88,0,66, +134,185,48,98,80,215,38,11,96,0,138,26,228,193,76,0,69,67,92,152,37,128,6, +168,107,147,4,48,1,165,13,114,96,118,0,44,161,174,76,12,192,7,148,53,201, +129,88,1,26,134,165,80,130,80,31,255,241,69,224,0,0,0,0,0,0,124,63,174,32, 0,0,0,0,0,0,120,63,175,98,7,140,16,116,194,7,12,48,108,196,6,140,80,100, 198,6,12,112,92,200,5,140,149,192,202,91,204,181,184,204,91,76,213,176,206, 90,204,240,84,208,5,13,9,124,210,43,13,24,64,226,131,205,112,56,216,3,77, 152,48,218,130,205,184,40,220,130,77,216,32,222,129,205,248,24,224,129,78, -25,214,163,226,90,80,145,104,65,37,157,0,150,99,242,89,78,73,100,58,37,140, -236,150,35,194,88,79,73,96,69,37,125,12,122,188,134,62,0,2,165,68,39,255, -255,193,43,67,0,0,80,127,192,58,182,216,80,0,21,59,154,64,0,107,76,200,172, -180,146,176,198,138,187,43,42,204,136,170,181,146,168,214,80,0,26,155,81, -42,77,4,168,180,20,0,6,160,206,74,123,73,64,0,127,255,4,10,153,219,28,198, -163,184,130,140,224,10,43,144,40,141,164,161,183,18,132,222,64,161,127,128, -0,63,225,1,109,74,8,137,71,56,5,4,213,20,3,115,233,249,177,240,80,255,192, +25,214,164,2,90,81,17,104,67,37,157,8,150,100,18,89,78,201,100,60,37,140, +244,150,35,226,88,79,201,96,71,37,125,20,122,188,138,62,0,2,165,70,39,255, +255,193,43,67,0,0,80,127,192,58,182,220,80,0,21,59,170,64,0,107,77,8,172, +181,146,176,202,138,187,59,42,204,200,170,182,146,168,218,80,0,26,155,97, +42,77,68,168,181,20,0,6,160,210,74,123,89,64,0,127,255,4,10,153,219,157,70, +163,185,130,140,228,10,43,160,40,141,228,161,184,18,132,226,64,161,127,128, +0,63,225,1,109,74,8,137,71,58,5,4,221,20,3,147,233,249,193,240,80,255,192, 6,120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156, 131,2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64, 207,192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10, 88,8,106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50, -135,195,224,127,196,2,87,132,17,82,143,20,10,44,80,36,239,196,147,63,146, -119,0,125,49,129,52,152,64,154,128,0,201,96,137,36,131,36,142,17,18,40,82, -77,97,145,33,135,68,130,37,17,247,208,71,159,65,29,125,8,0,12,113,244,32,0, -49,184,176,70,162,16,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19, -0,81,191,197,140,192,255,255,255,255,255,255,239,127,140,64,1,0,0,0,0,0,0, -0,139,192,0,0,0,0,0,0,248,127,138,192,0,0,0,0,0,0,240,127,139,64,0,0,0,0,0, -0,240,255,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,96,37,25,120,148,86, -16,69,23,73,19,92,36,73,124,129,71,255,0,56,136,233,34,3,223,208,241,192,3, +135,227,224,127,196,2,87,132,17,82,143,24,10,44,96,36,240,4,147,64,146,119, +4,125,49,131,52,152,65,154,128,0,201,97,9,36,133,36,142,25,18,40,114,77,98, +17,33,137,68,130,45,17,247,240,71,159,193,29,127,8,0,12,113,252,32,0,49, +184,208,70,162,144,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,0, +81,191,197,140,192,255,255,255,255,255,255,239,127,140,64,1,0,0,0,0,0,0,0, +139,192,0,0,0,0,0,0,248,127,138,192,0,0,0,0,0,0,240,127,139,64,0,0,0,0,0,0, +240,255,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,98,37,25,128,148,86,48, +69,23,201,19,94,36,73,132,129,71,255,0,56,136,233,34,3,223,208,241,192,3, 254,56,18,188,128,0,0,0,0,0,15,135,251,104,228,128,135,18,4,0,6,26,72,16,0, 42,49,32,64,0,225,132,129,0,4,133,146,4,0,21,210,72,16,0,103,65,32,64,1, 220,228,100,162,146,130,20,74,8,72,248,64,2,33,3,225,0,9,131,143,132,0,42, @@ -12318,9 +12320,9 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { 33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0, 133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92, 195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225, -132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,240,71,19,201,40, -239,64,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,137,129,109,203,140, -11,78,94,96,13,28,200,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47, +132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40, +239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139, +203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47, 252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183, 54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127, 206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15, @@ -12328,126 +12330,51 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { 144,26,208,59,206,126,191,144,139,185,143,218,176,63,160,138,217,81,197, 125,207,218,144,3,185,73,133,94,242,246,207,218,112,6,11,81,21,62,200,66, 80,26,80,51,78,223,217,167,168,57,143,218,48,51,78,223,217,167,168,61,143, -210,104,39,17,158,156,80,0,22,114,113,64,0,153,169,197,0,3,102,40,33,150, -156,80,0,70,82,113,64,1,89,41,197,0,6,100,39,20,0,29,142,156,80,0,134,50, -98,243,21,53,121,136,160,144,0,22,26,120,24,73,197,0,9,96,167,20,0,41,128, -156,80,0,181,250,113,64,3,1,255,254,0,81,20,100,47,145,216,23,255,240,0,11, -255,248,0,3,255,252,81,252,0,0,0,0,8,4,252,68,0,129,167,1,26,144,9,165,0, -26,177,199,197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52, -39,32,84,223,192,15,59,30,129,156,115,6,81,160,7,253,40,0,5,81,252,0,1,255, -78,0,84,113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,66,0,3,69, -117,0,85,159,192,0,31,245,97,10,100,0,0,0,0,0,0,0,32,10,164,130,97,221,191, -113,3,20,146,12,18,200,47,74,30,23,37,15,128,0,143,146,135,192,0,133,169, -67,224,0,98,196,161,240,0,65,90,80,248,0,41,63,255,194,109,65,11,137,191, -174,45,153,98,242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188, -185,111,228,131,70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255, -174,0,25,168,194,64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233, -0,32,54,139,164,0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139, -164,0,140,208,46,144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200, -50,208,2,19,24,203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64, -127,255,128,21,38,73,7,1,132,128,0,133,105,252,19,140,0,0,0,0,0,0,15,3,240, -25,127,102,0,1,91,127,4,227,0,0,0,0,0,0,3,192,252,6,95,218,128,0,87,31,193, -56,192,0,0,0,0,0,0,240,63,1,151,246,224,0,21,215,240,78,48,0,0,0,0,0,0,0, -16,0,101,253,200,0,5,121,252,19,140,0,0,0,0,0,0,0,4,0,25,127,118,0,1,95, -127,4,227,0,0,0,0,0,0,0,65,0,6,95,222,128,0,88,31,193,56,192,0,0,0,0,0,0, -16,64,1,151,247,224,0,22,23,240,78,48,0,0,0,0,0,0,4,16,0,101,254,8,0,5,137, -252,19,140,0,0,0,0,0,0,2,4,0,25,127,134,0,1,99,127,0,89,218,146,20,74,228, -80,171,17,64,162,132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32, -152,23,72,0,10,92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18, -76,93,32,1,73,33,116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104, -225,116,128,2,35,69,210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128, -10,162,69,218,0,58,136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18, -132,25,104,0,138,12,101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0, -145,252,101,160,3,71,225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101, -160,1,135,161,152,128,2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180, -117,150,57,214,0,157,85,98,112,80,137,241,66,128,0,166,213,33,53,24,66,121, -106,0, +210,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160, +80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243, +21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0, +181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0, +3,255,252,81,252,0,0,0,0,8,4,252,68,0,129,167,1,26,144,9,165,0,26,177,199, +197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84, +223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84, +113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85, +159,192,0,31,245,97,10,100,0,0,0,0,0,0,0,32,10,164,130,97,221,191,113,3,20, +178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98, +196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98, +242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131, +70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194, +64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164, +0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46, +144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24, +203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21, +38,81,7,1,132,128,0,133,105,252,19,140,0,0,0,0,0,0,15,3,240,25,127,102,0,1, +91,127,4,227,0,0,0,0,0,0,3,192,252,6,95,218,128,0,87,31,193,56,192,0,0,0,0, +0,0,240,63,1,151,246,224,0,21,215,240,78,48,0,0,0,0,0,0,0,16,0,101,253,200, +0,5,121,252,19,140,0,0,0,0,0,0,0,4,0,25,127,118,0,1,95,127,4,227,0,0,0,0,0, +0,0,65,0,6,95,222,128,0,88,31,193,56,192,0,0,0,0,0,0,16,64,1,151,247,224,0, +22,23,240,78,48,0,0,0,0,0,0,4,16,0,101,254,8,0,5,137,252,19,140,0,0,0,0,0, +0,2,4,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132, +248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93, +32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116, +128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210, +0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25, +98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160, +3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150, +128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158, +70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98, +112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0, }; #ifdef DUK_USE_BUILTIN_INITJS -DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = { -47,42,10,32,42,32,32,73,110,105,116,32,99,111,100,101,32,102,111,114,32, -108,101,103,97,99,121,32,99,111,109,112,97,116,105,98,105,108,105,116,121, -46,10,32,42,10,32,42,32,32,67,111,109,112,97,116,105,98,105,108,105,116, -121,32,112,114,111,112,101,114,116,105,101,115,32,47,32,119,114,97,112,112, -101,114,32,102,117,110,99,116,105,111,110,115,32,104,101,114,101,32,97,108, -108,111,119,32,68,117,107,116,97,112,101,32,116,111,32,114,101,109,97,105, -110,10,32,42,32,32,99,111,109,112,97,116,105,98,108,101,32,102,111,114,32, -117,115,101,114,32,99,111,100,101,32,119,104,101,110,32,99,111,114,101,32, -102,101,97,116,117,114,101,115,32,97,114,101,32,99,104,97,110,103,101,100, -44,32,119,105,116,104,111,117,116,32,98,117,114,100,101,110,105,110,103,10, -32,42,32,32,116,104,101,32,109,97,105,110,32,67,32,99,111,100,101,32,119, -105,116,104,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,115,116, -117,102,102,46,10,32,42,10,32,42,32,32,84,104,105,115,32,102,105,108,101, -32,105,115,32,109,105,110,105,102,105,101,100,32,119,105,116,104,32,85,103, -108,105,102,121,74,83,32,111,114,32,116,104,101,32,99,108,111,115,117,114, -101,32,99,111,109,112,105,108,101,114,46,32,32,66,111,116,104,32,119,105, -108,108,10,32,42,32,32,114,101,110,97,109,101,32,118,97,114,105,97,98,108, -101,115,44,32,114,101,109,111,118,101,32,99,111,109,109,101,110,116,115,44, -32,97,110,100,32,97,114,101,32,99,108,101,118,101,114,32,101,110,111,117, -103,104,32,116,111,32,100,114,111,112,32,97,110,121,10,32,42,32,32,34,105, -102,32,40,102,97,108,115,101,41,32,123,32,46,46,46,32,125,34,32,98,108,111, -99,107,115,32,97,108,116,111,103,101,116,104,101,114,44,32,115,111,32,116, -104,97,116,39,115,32,97,110,32,101,102,102,101,99,116,105,118,101,32,119, -97,121,32,116,111,10,32,42,32,32,100,105,115,97,98,108,101,32,99,117,114, -114,101,110,116,108,121,32,117,110,110,101,101,100,101,100,32,99,111,100, -101,46,10,32,42,47,10,10,40,102,117,110,99,116,105,111,110,40,71,44,32,68, -41,32,123,10,32,32,32,32,39,117,115,101,32,115,116,114,105,99,116,39,59,10, -10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,101,102,40,111,98,106, -101,99,116,44,32,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32, -32,32,32,32,32,32,32,79,98,106,101,99,116,46,100,101,102,105,110,101,80, -114,111,112,101,114,116,121,40,111,98,106,101,99,116,44,32,110,97,109,101, -44,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,118,97,108,117,101,58,32, -118,97,108,117,101,44,10,32,32,32,32,32,32,32,32,32,32,32,32,119,114,105, -116,97,98,108,101,58,32,116,114,117,101,44,10,32,32,32,32,32,32,32,32,32, -32,32,32,101,110,117,109,101,114,97,98,108,101,58,32,102,97,108,115,101,44, -10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,102,105,103,117,114,97, -98,108,101,58,32,116,114,117,101,10,32,32,32,32,32,32,32,32,125,41,59,10, -32,32,32,32,125,10,10,32,32,32,32,102,117,110,99,116,105,111,110,32,100, -101,102,68,40,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,32, -32,32,32,32,32,32,100,101,102,40,68,44,32,110,97,109,101,44,32,118,97,108, -117,101,41,59,10,32,32,32,32,125,10,10,32,32,32,32,47,47,32,67,111,109,112, -97,116,105,98,105,108,105,116,121,32,102,111,114,32,39,99,111,110,115,111, -108,101,46,108,111,103,39,46,10,32,32,32,32,105,102,32,40,102,97,108,115, -101,41,32,123,10,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,32,61, -32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,103,58,32,102,117, -110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32, -32,32,32,32,112,114,105,110,116,40,65,114,114,97,121,46,112,114,111,116, -111,116,121,112,101,46,106,111,105,110,46,99,97,108,108,40,97,114,103,117, -109,101,110,116,115,44,32,39,32,39,41,41,59,10,32,32,32,32,32,32,32,32,32, -32,32,32,125,10,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,125,10,10,32, -32,32,32,47,47,32,68,117,107,116,97,112,101,46,108,105,110,101,40,41,32, -119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,68,117,107,116,97, -112,101,32,48,46,49,49,46,48,44,32,104,101,114,101,39,115,32,97,110,32,101, -120,97,109,112,108,101,10,32,32,32,32,47,47,32,114,101,112,108,97,99,101, -109,101,110,116,32,117,115,101,114,32,99,111,100,101,32,99,111,117,108,100, -32,117,115,101,46,10,32,32,32,32,105,102,32,40,102,97,108,115,101,41,32, -123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,108,105,110,101, -39,44,32,102,117,110,99,116,105,111,110,32,40,41,32,123,10,32,32,32,32,32, -32,32,32,32,32,32,32,39,117,115,101,32,100,117,107,32,110,111,116,97,105, -108,39,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,47,42,32,84,97,105,108, -32,99,97,108,108,115,32,97,114,101,32,112,114,101,118,101,110,116,101,100, -32,116,111,32,101,110,115,117,114,101,32,99,97,108,108,105,110,103,32,97, -99,116,105,118,97,116,105,111,110,32,101,120,105,115,116,115,46,10,32,32, -32,32,32,32,32,32,32,32,32,32,32,42,32,67,97,108,108,32,115,116,97,99,107, -32,105,110,100,105,99,101,115,58,32,45,49,32,61,32,68,117,107,116,97,112, -101,46,97,99,116,44,32,45,50,32,61,32,103,101,116,67,117,114,114,101,110, -116,76,105,110,101,44,32,45,51,32,61,32,99,97,108,108,101,114,10,32,32,32, -32,32,32,32,32,32,32,32,32,32,42,47,10,10,32,32,32,32,32,32,32,32,32,32,32, -32,114,101,116,117,114,110,32,40,68,117,107,116,97,112,101,46,97,99,116,40, -45,51,41,32,124,124,32,123,125,41,46,108,105,110,101,78,117,109,98,101,114, -59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,10,10,32,32,32, -32,47,47,32,76,111,103,103,101,114,32,111,98,106,101,99,116,32,102,111,114, -32,67,32,99,111,100,101,32,112,114,111,118,105,100,101,100,32,98,121,32, -105,110,105,116,32,99,111,100,101,32,110,111,119,46,10,32,32,32,32,105,102, -32,40,116,114,117,101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40, -68,46,76,111,103,103,101,114,44,32,39,99,108,111,103,39,44,32,110,101,119, -32,68,46,76,111,103,103,101,114,40,39,67,39,41,41,59,10,32,32,32,32,125,10, -10,32,32,32,32,47,47,32,84,114,97,99,107,105,110,103,32,116,97,98,108,101, -32,102,111,114,32,67,111,109,109,111,110,74,83,32,109,111,100,117,108,101, -32,108,111,97,100,105,110,103,46,10,32,32,32,32,105,102,32,40,116,114,117, -101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,109, -111,100,76,111,97,100,101,100,39,44,32,123,125,41,59,10,32,32,32,32,125,10, -125,41,40,116,104,105,115,44,32,68,117,107,116,97,112,101,41,59,10,0, +DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = { +40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116, +105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101, +102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97, +108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117, +109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98, +108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99, +108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34, +41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,123,125,41, +125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,59,10,0, }; #endif /* DUK_USE_BUILTIN_INITJS */ #elif defined(DUK_USE_DOUBLE_BE) @@ -12572,20 +12499,20 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[2624] = { 32,76,71,64,156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44, 147,32,134,226,17,114,33,202,134,129,107,192,202,232,160,180,104,166,135, 52,72,40,144,213,33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34, -98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,74,185,3,45, -142,133,144,150,68,206,81,44,18,145,68,230,202,100,35,104,195,18,239,116, -102,114,94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161, -10,80,46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222, -1,40,6,33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104, -17,112,130,44,96, +98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153, +42,228,12,182,58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114, +94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80, +46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6, +33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112, +130,44,96, }; /* to convert a heap stridx to a token number, subtract * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. */ -/* native functions: 147 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { +/* native functions: 149 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_array_constructor, duk_bi_array_constructor_is_array, duk_bi_array_prototype_concat, @@ -12633,9 +12560,11 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { duk_bi_duktape_object_info, duk_bi_error_constructor_shared, duk_bi_error_prototype_filename_getter, + duk_bi_error_prototype_filename_setter, duk_bi_error_prototype_linenumber_getter, - duk_bi_error_prototype_nop_setter, + duk_bi_error_prototype_linenumber_setter, duk_bi_error_prototype_stack_getter, + duk_bi_error_prototype_stack_setter, duk_bi_error_prototype_to_string, duk_bi_function_constructor, duk_bi_function_prototype, @@ -12736,38 +12665,38 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { }; DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { -105,195,75,16,121,40,105,51,14,252,104,52,8,131,72,0,115,225,65,165,236,55, -243,6,145,32,210,24,210,182,25,249,35,120,216,99,226,13,78,225,116,177,164, +105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55, +243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164, 180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96, 3,37,26,75,109,172,0,108,163,73,109,177,128,14,148,105,45,181,176,1,242, -144,56,209,32,94,6,167,101,98,80,211,24,1,250,67,72,168,67,232,13,46,128, -47,162,52,164,0,62,80,163,72,128,61,40,107,26,7,37,20,53,200,131,88,0,66, -134,185,16,98,80,215,34,11,96,0,138,26,228,65,76,0,69,67,92,136,37,128,6, -168,107,145,4,48,1,165,13,114,32,118,0,44,161,174,68,12,192,7,148,53,200, -129,88,1,26,134,165,48,130,80,31,255,241,69,224,63,252,0,0,0,0,0,0,46,32, +144,56,209,36,94,6,167,133,98,80,211,28,1,250,67,72,168,67,232,13,46,192, +47,162,52,165,0,62,80,163,72,128,61,40,107,26,7,37,20,53,201,131,88,0,66, +134,185,48,98,80,215,38,11,96,0,138,26,228,193,76,0,69,67,92,152,37,128,6, +168,107,147,4,48,1,165,13,114,96,118,0,44,161,174,76,12,192,7,148,53,201, +129,88,1,26,134,165,80,130,80,31,255,241,69,224,63,252,0,0,0,0,0,0,46,32, 63,248,0,0,0,0,0,0,47,98,7,140,16,116,194,7,12,48,108,196,6,140,80,100,198, 6,12,112,92,200,5,140,149,192,202,91,204,181,184,204,91,76,213,176,206,90, 204,240,84,208,5,13,9,124,210,43,13,24,64,226,131,205,112,56,216,3,77,152, 48,218,130,205,184,40,220,130,77,216,32,222,129,205,248,24,224,129,78,25, -214,163,226,90,80,145,104,65,37,157,0,150,99,242,89,78,73,100,58,37,140, -236,150,35,194,88,79,73,96,69,37,125,12,122,188,134,62,0,2,165,68,39,255, -255,193,43,67,0,0,80,127,192,58,182,216,80,0,21,59,154,64,0,107,76,200,172, -180,146,176,198,138,187,43,42,204,136,170,181,146,168,214,80,0,26,155,81, -42,77,4,168,180,20,0,6,160,206,74,123,73,64,0,127,255,4,10,153,219,28,198, -163,184,130,140,224,10,43,144,40,141,164,161,183,18,132,222,64,161,127,128, -0,63,225,1,109,74,8,137,71,56,5,4,213,20,3,115,233,249,177,240,80,255,192, -6,120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156, -131,2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64, -207,192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10, -88,8,106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50, -135,195,224,127,196,2,87,132,17,82,143,20,10,44,80,36,239,196,147,63,146, -119,0,125,49,129,52,152,64,154,128,0,201,96,137,36,131,36,142,17,18,40,82, -77,97,145,33,135,68,130,37,17,247,208,71,159,65,29,125,8,0,12,113,244,32,0, -49,184,176,70,162,16,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19, -0,81,191,197,140,192,127,239,255,255,255,255,255,255,140,64,0,0,0,0,0,0,0, -1,139,192,127,248,0,0,0,0,0,0,138,192,127,240,0,0,0,0,0,0,139,64,255,240,0, -0,0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,96,37,25,120,148,86, -16,69,23,73,19,92,36,73,124,129,71,255,0,56,136,233,34,3,223,208,241,192,3, +214,164,2,90,81,17,104,67,37,157,8,150,100,18,89,78,201,100,60,37,140,244, +150,35,226,88,79,201,96,71,37,125,20,122,188,138,62,0,2,165,70,39,255,255, +193,43,67,0,0,80,127,192,58,182,220,80,0,21,59,170,64,0,107,77,8,172,181, +146,176,202,138,187,59,42,204,200,170,182,146,168,218,80,0,26,155,97,42,77, +68,168,181,20,0,6,160,210,74,123,89,64,0,127,255,4,10,153,219,157,70,163, +185,130,140,228,10,43,160,40,141,228,161,184,18,132,226,64,161,127,128,0, +63,225,1,109,74,8,137,71,58,5,4,221,20,3,147,233,249,193,240,80,255,192,6, +120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156,131, +2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64,207, +192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10,88,8, +106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50,135, +227,224,127,196,2,87,132,17,82,143,24,10,44,96,36,240,4,147,64,146,119,4, +125,49,131,52,152,65,154,128,0,201,97,9,36,133,36,142,25,18,40,114,77,98, +17,33,137,68,130,45,17,247,240,71,159,193,29,127,8,0,12,113,252,32,0,49, +184,208,70,162,144,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,0, +81,191,197,140,192,127,239,255,255,255,255,255,255,140,64,0,0,0,0,0,0,0,1, +139,192,127,248,0,0,0,0,0,0,138,192,127,240,0,0,0,0,0,0,139,64,255,240,0,0, +0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,98,37,25,128,148,86,48, +69,23,201,19,94,36,73,132,129,71,255,0,56,136,233,34,3,223,208,241,192,3, 254,56,18,188,135,255,128,0,0,0,0,0,11,104,228,128,135,18,4,0,6,26,72,16,0, 42,49,32,64,0,225,132,129,0,4,133,146,4,0,21,210,72,16,0,103,65,32,64,1, 220,228,100,162,146,130,20,74,8,72,248,64,2,33,3,225,0,9,131,143,132,0,42, @@ -12778,9 +12707,9 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { 33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0, 133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92, 195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225, -132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,240,71,19,201,40, -239,64,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,137,129,109,203,140, -11,78,94,96,13,28,200,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47, +132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40, +239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139, +203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47, 252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183, 54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127, 206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15, @@ -12788,125 +12717,51 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { 69,154,208,15,249,139,144,191,190,142,123,218,176,15,253,197,81,217,74,224, 191,154,144,15,246,242,222,197,73,185,67,154,112,16,2,72,126,213,17,11,70, 26,80,15,249,168,39,153,159,206,243,90,48,15,253,168,39,153,159,206,243,82, -104,39,17,158,156,80,0,22,114,113,64,0,153,169,197,0,3,102,40,33,150,156, -80,0,70,82,113,64,1,89,41,197,0,6,100,39,20,0,29,142,156,80,0,134,50,98, -243,21,53,121,136,160,144,0,22,26,120,24,73,197,0,9,96,167,20,0,41,128,156, -80,0,181,250,113,64,3,1,255,254,0,81,20,100,47,145,216,23,255,240,0,11,255, -248,0,3,255,252,81,252,4,12,68,248,0,0,0,0,0,129,167,1,26,144,9,165,0,26, -177,199,197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39, -32,84,223,192,15,59,30,129,156,115,6,81,160,7,253,40,0,5,81,252,0,1,255,78, -0,84,113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,66,0,3,69,117,0, -85,159,192,0,31,245,97,10,100,32,0,0,0,0,0,0,0,10,164,130,97,221,191,113,3, -20,146,12,18,200,47,74,30,23,37,15,128,0,143,146,135,192,0,133,169,67,224, -0,98,196,161,240,0,65,90,80,248,0,41,63,255,194,109,65,11,137,191,174,45, -153,98,242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111, -228,131,70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25, -168,194,64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54, -139,164,0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0, -140,208,46,144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50, -208,2,19,24,203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127, -255,128,21,38,73,7,1,132,128,0,133,105,252,19,140,3,255,0,0,0,0,0,0,0,25, -127,102,0,1,91,127,4,227,0,255,192,0,0,0,0,0,0,6,95,218,128,0,87,31,193,56, -192,63,240,0,0,0,0,0,0,1,151,246,224,0,21,215,240,78,48,16,0,0,0,0,0,0,0,0, -101,253,200,0,5,121,252,19,140,4,0,0,0,0,0,0,0,0,25,127,118,0,1,95,127,4, -227,1,0,64,0,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,64,16,0,0,0,0,0,0,1, -151,247,224,0,22,23,240,78,48,16,4,0,0,0,0,0,0,0,101,254,8,0,5,137,252,19, -140,4,2,0,0,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,146,20,74,228,80,171, -17,64,162,132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23, -72,0,10,92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32, -1,73,33,116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128, -2,35,69,210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218, -0,58,136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138, -12,101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3, -71,225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152, -128,2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,150,57,214,0, -157,85,98,112,80,137,241,66,128,0,166,213,33,53,24,66,121,106,0, +104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,80, +0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,21, +61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,181, +250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,3, +255,252,81,252,4,12,68,248,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199, +197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84, +223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84, +113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85, +159,192,0,31,245,97,10,100,32,0,0,0,0,0,0,0,10,164,130,97,221,191,113,3,20, +178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98, +196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98, +242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131, +70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194, +64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164, +0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46, +144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24, +203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21, +38,81,7,1,132,128,0,133,105,252,19,140,3,255,0,0,0,0,0,0,0,25,127,102,0,1, +91,127,4,227,0,255,192,0,0,0,0,0,0,6,95,218,128,0,87,31,193,56,192,63,240, +0,0,0,0,0,0,1,151,246,224,0,21,215,240,78,48,16,0,0,0,0,0,0,0,0,101,253, +200,0,5,121,252,19,140,4,0,0,0,0,0,0,0,0,25,127,118,0,1,95,127,4,227,1,0, +64,0,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,64,16,0,0,0,0,0,0,1,151,247, +224,0,22,23,240,78,48,16,4,0,0,0,0,0,0,0,101,254,8,0,5,137,252,19,140,4,2, +0,0,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166, +132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10, +92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33, +116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69, +210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58, +136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12, +101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71, +225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128, +2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157, +87,98,112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0, }; #ifdef DUK_USE_BUILTIN_INITJS -DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = { -47,42,10,32,42,32,32,73,110,105,116,32,99,111,100,101,32,102,111,114,32, -108,101,103,97,99,121,32,99,111,109,112,97,116,105,98,105,108,105,116,121, -46,10,32,42,10,32,42,32,32,67,111,109,112,97,116,105,98,105,108,105,116, -121,32,112,114,111,112,101,114,116,105,101,115,32,47,32,119,114,97,112,112, -101,114,32,102,117,110,99,116,105,111,110,115,32,104,101,114,101,32,97,108, -108,111,119,32,68,117,107,116,97,112,101,32,116,111,32,114,101,109,97,105, -110,10,32,42,32,32,99,111,109,112,97,116,105,98,108,101,32,102,111,114,32, -117,115,101,114,32,99,111,100,101,32,119,104,101,110,32,99,111,114,101,32, -102,101,97,116,117,114,101,115,32,97,114,101,32,99,104,97,110,103,101,100, -44,32,119,105,116,104,111,117,116,32,98,117,114,100,101,110,105,110,103,10, -32,42,32,32,116,104,101,32,109,97,105,110,32,67,32,99,111,100,101,32,119, -105,116,104,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,115,116, -117,102,102,46,10,32,42,10,32,42,32,32,84,104,105,115,32,102,105,108,101, -32,105,115,32,109,105,110,105,102,105,101,100,32,119,105,116,104,32,85,103, -108,105,102,121,74,83,32,111,114,32,116,104,101,32,99,108,111,115,117,114, -101,32,99,111,109,112,105,108,101,114,46,32,32,66,111,116,104,32,119,105, -108,108,10,32,42,32,32,114,101,110,97,109,101,32,118,97,114,105,97,98,108, -101,115,44,32,114,101,109,111,118,101,32,99,111,109,109,101,110,116,115,44, -32,97,110,100,32,97,114,101,32,99,108,101,118,101,114,32,101,110,111,117, -103,104,32,116,111,32,100,114,111,112,32,97,110,121,10,32,42,32,32,34,105, -102,32,40,102,97,108,115,101,41,32,123,32,46,46,46,32,125,34,32,98,108,111, -99,107,115,32,97,108,116,111,103,101,116,104,101,114,44,32,115,111,32,116, -104,97,116,39,115,32,97,110,32,101,102,102,101,99,116,105,118,101,32,119, -97,121,32,116,111,10,32,42,32,32,100,105,115,97,98,108,101,32,99,117,114, -114,101,110,116,108,121,32,117,110,110,101,101,100,101,100,32,99,111,100, -101,46,10,32,42,47,10,10,40,102,117,110,99,116,105,111,110,40,71,44,32,68, -41,32,123,10,32,32,32,32,39,117,115,101,32,115,116,114,105,99,116,39,59,10, -10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,101,102,40,111,98,106, -101,99,116,44,32,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32, -32,32,32,32,32,32,32,79,98,106,101,99,116,46,100,101,102,105,110,101,80, -114,111,112,101,114,116,121,40,111,98,106,101,99,116,44,32,110,97,109,101, -44,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,118,97,108,117,101,58,32, -118,97,108,117,101,44,10,32,32,32,32,32,32,32,32,32,32,32,32,119,114,105, -116,97,98,108,101,58,32,116,114,117,101,44,10,32,32,32,32,32,32,32,32,32, -32,32,32,101,110,117,109,101,114,97,98,108,101,58,32,102,97,108,115,101,44, -10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,102,105,103,117,114,97, -98,108,101,58,32,116,114,117,101,10,32,32,32,32,32,32,32,32,125,41,59,10, -32,32,32,32,125,10,10,32,32,32,32,102,117,110,99,116,105,111,110,32,100, -101,102,68,40,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,32, -32,32,32,32,32,32,100,101,102,40,68,44,32,110,97,109,101,44,32,118,97,108, -117,101,41,59,10,32,32,32,32,125,10,10,32,32,32,32,47,47,32,67,111,109,112, -97,116,105,98,105,108,105,116,121,32,102,111,114,32,39,99,111,110,115,111, -108,101,46,108,111,103,39,46,10,32,32,32,32,105,102,32,40,102,97,108,115, -101,41,32,123,10,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,32,61, -32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,103,58,32,102,117, -110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32, -32,32,32,32,112,114,105,110,116,40,65,114,114,97,121,46,112,114,111,116, -111,116,121,112,101,46,106,111,105,110,46,99,97,108,108,40,97,114,103,117, -109,101,110,116,115,44,32,39,32,39,41,41,59,10,32,32,32,32,32,32,32,32,32, -32,32,32,125,10,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,125,10,10,32, -32,32,32,47,47,32,68,117,107,116,97,112,101,46,108,105,110,101,40,41,32, -119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,68,117,107,116,97, -112,101,32,48,46,49,49,46,48,44,32,104,101,114,101,39,115,32,97,110,32,101, -120,97,109,112,108,101,10,32,32,32,32,47,47,32,114,101,112,108,97,99,101, -109,101,110,116,32,117,115,101,114,32,99,111,100,101,32,99,111,117,108,100, -32,117,115,101,46,10,32,32,32,32,105,102,32,40,102,97,108,115,101,41,32, -123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,108,105,110,101, -39,44,32,102,117,110,99,116,105,111,110,32,40,41,32,123,10,32,32,32,32,32, -32,32,32,32,32,32,32,39,117,115,101,32,100,117,107,32,110,111,116,97,105, -108,39,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,47,42,32,84,97,105,108, -32,99,97,108,108,115,32,97,114,101,32,112,114,101,118,101,110,116,101,100, -32,116,111,32,101,110,115,117,114,101,32,99,97,108,108,105,110,103,32,97, -99,116,105,118,97,116,105,111,110,32,101,120,105,115,116,115,46,10,32,32, -32,32,32,32,32,32,32,32,32,32,32,42,32,67,97,108,108,32,115,116,97,99,107, -32,105,110,100,105,99,101,115,58,32,45,49,32,61,32,68,117,107,116,97,112, -101,46,97,99,116,44,32,45,50,32,61,32,103,101,116,67,117,114,114,101,110, -116,76,105,110,101,44,32,45,51,32,61,32,99,97,108,108,101,114,10,32,32,32, -32,32,32,32,32,32,32,32,32,32,42,47,10,10,32,32,32,32,32,32,32,32,32,32,32, -32,114,101,116,117,114,110,32,40,68,117,107,116,97,112,101,46,97,99,116,40, -45,51,41,32,124,124,32,123,125,41,46,108,105,110,101,78,117,109,98,101,114, -59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,10,10,32,32,32, -32,47,47,32,76,111,103,103,101,114,32,111,98,106,101,99,116,32,102,111,114, -32,67,32,99,111,100,101,32,112,114,111,118,105,100,101,100,32,98,121,32, -105,110,105,116,32,99,111,100,101,32,110,111,119,46,10,32,32,32,32,105,102, -32,40,116,114,117,101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40, -68,46,76,111,103,103,101,114,44,32,39,99,108,111,103,39,44,32,110,101,119, -32,68,46,76,111,103,103,101,114,40,39,67,39,41,41,59,10,32,32,32,32,125,10, -10,32,32,32,32,47,47,32,84,114,97,99,107,105,110,103,32,116,97,98,108,101, -32,102,111,114,32,67,111,109,109,111,110,74,83,32,109,111,100,117,108,101, -32,108,111,97,100,105,110,103,46,10,32,32,32,32,105,102,32,40,116,114,117, -101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,109, -111,100,76,111,97,100,101,100,39,44,32,123,125,41,59,10,32,32,32,32,125,10, -125,41,40,116,104,105,115,44,32,68,117,107,116,97,112,101,41,59,10,0, +DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = { +40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116, +105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101, +102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97, +108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117, +109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98, +108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99, +108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34, +41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,123,125,41, +125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,59,10,0, }; #endif /* DUK_USE_BUILTIN_INITJS */ #elif defined(DUK_USE_DOUBLE_ME) @@ -13031,20 +12886,20 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[2624] = { 32,76,71,64,156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44, 147,32,134,226,17,114,33,202,134,129,107,192,202,232,160,180,104,166,135, 52,72,40,144,213,33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34, -98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,74,185,3,45, -142,133,144,150,68,206,81,44,18,145,68,230,202,100,35,104,195,18,239,116, -102,114,94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161, -10,80,46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222, -1,40,6,33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104, -17,112,130,44,96, +98,57,38,116,72,179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153, +42,228,12,182,58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114, +94,100,104,228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80, +46,68,82,24,245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6, +33,223,20,84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112, +130,44,96, }; /* to convert a heap stridx to a token number, subtract * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. */ -/* native functions: 147 */ -DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { +/* native functions: 149 */ +DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = { duk_bi_array_constructor, duk_bi_array_constructor_is_array, duk_bi_array_prototype_concat, @@ -13092,9 +12947,11 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { duk_bi_duktape_object_info, duk_bi_error_constructor_shared, duk_bi_error_prototype_filename_getter, + duk_bi_error_prototype_filename_setter, duk_bi_error_prototype_linenumber_getter, - duk_bi_error_prototype_nop_setter, + duk_bi_error_prototype_linenumber_setter, duk_bi_error_prototype_stack_getter, + duk_bi_error_prototype_stack_setter, duk_bi_error_prototype_to_string, duk_bi_function_constructor, duk_bi_function_prototype, @@ -13195,38 +13052,38 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[147] = { }; DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { -105,195,75,16,121,40,105,51,14,252,104,52,8,131,72,0,115,225,65,165,236,55, -243,6,145,32,210,24,210,182,25,249,35,120,216,99,226,13,78,225,116,177,164, +105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55, +243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164, 180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96, 3,37,26,75,109,172,0,108,163,73,109,177,128,14,148,105,45,181,176,1,242, -144,56,209,32,94,6,167,101,98,80,211,24,1,250,67,72,168,67,232,13,46,128, -47,162,52,164,0,62,80,163,72,128,61,40,107,26,7,37,20,53,200,131,88,0,66, -134,185,16,98,80,215,34,11,96,0,138,26,228,65,76,0,69,67,92,136,37,128,6, -168,107,145,4,48,1,165,13,114,32,118,0,44,161,174,68,12,192,7,148,53,200, -129,88,1,26,134,165,48,130,80,31,255,241,69,224,0,0,124,63,128,0,0,0,46,32, +144,56,209,36,94,6,167,133,98,80,211,28,1,250,67,72,168,67,232,13,46,192, +47,162,52,165,0,62,80,163,72,128,61,40,107,26,7,37,20,53,201,131,88,0,66, +134,185,48,98,80,215,38,11,96,0,138,26,228,193,76,0,69,67,92,152,37,128,6, +168,107,147,4,48,1,165,13,114,96,118,0,44,161,174,76,12,192,7,148,53,201, +129,88,1,26,134,165,80,130,80,31,255,241,69,224,0,0,124,63,128,0,0,0,46,32, 0,0,120,63,128,0,0,0,47,98,7,140,16,116,194,7,12,48,108,196,6,140,80,100, 198,6,12,112,92,200,5,140,149,192,202,91,204,181,184,204,91,76,213,176,206, 90,204,240,84,208,5,13,9,124,210,43,13,24,64,226,131,205,112,56,216,3,77, 152,48,218,130,205,184,40,220,130,77,216,32,222,129,205,248,24,224,129,78, -25,214,163,226,90,80,145,104,65,37,157,0,150,99,242,89,78,73,100,58,37,140, -236,150,35,194,88,79,73,96,69,37,125,12,122,188,134,62,0,2,165,68,39,255, -255,193,43,67,0,0,80,127,192,58,182,216,80,0,21,59,154,64,0,107,76,200,172, -180,146,176,198,138,187,43,42,204,136,170,181,146,168,214,80,0,26,155,81, -42,77,4,168,180,20,0,6,160,206,74,123,73,64,0,127,255,4,10,153,219,28,198, -163,184,130,140,224,10,43,144,40,141,164,161,183,18,132,222,64,161,127,128, -0,63,225,1,109,74,8,137,71,56,5,4,213,20,3,115,233,249,177,240,80,255,192, +25,214,164,2,90,81,17,104,67,37,157,8,150,100,18,89,78,201,100,60,37,140, +244,150,35,226,88,79,201,96,71,37,125,20,122,188,138,62,0,2,165,70,39,255, +255,193,43,67,0,0,80,127,192,58,182,220,80,0,21,59,170,64,0,107,77,8,172, +181,146,176,202,138,187,59,42,204,200,170,182,146,168,218,80,0,26,155,97, +42,77,68,168,181,20,0,6,160,210,74,123,89,64,0,127,255,4,10,153,219,157,70, +163,185,130,140,228,10,43,160,40,141,228,161,184,18,132,226,64,161,127,128, +0,63,225,1,109,74,8,137,71,58,5,4,221,20,3,147,233,249,193,240,80,255,192, 6,120,2,64,127,195,0,173,28,56,20,96,80,128,0,206,192,143,167,64,164,156, 131,2,112,14,125,55,9,4,216,40,19,80,180,77,3,9,51,13,94,153,7,159,76,64, 207,192,0,102,0,103,255,255,242,240,67,73,112,33,168,0,12,180,16,212,0,10, 88,8,106,0,7,43,4,53,0,4,149,4,31,128,0,202,66,15,255,255,194,137,254,0,50, -135,195,224,127,196,2,87,132,17,82,143,20,10,44,80,36,239,196,147,63,146, -119,0,125,49,129,52,152,64,154,128,0,201,96,137,36,131,36,142,17,18,40,82, -77,97,145,33,135,68,130,37,17,247,208,71,159,65,29,125,8,0,12,113,244,32,0, -49,184,176,70,162,16,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19, -0,81,191,197,140,192,255,255,239,127,255,255,255,255,140,64,0,0,0,0,1,0,0, -0,139,192,0,0,248,127,0,0,0,0,138,192,0,0,240,127,0,0,0,0,139,64,0,0,240, -255,0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,96,37,25,120,148,86, -16,69,23,73,19,92,36,73,124,129,71,255,0,56,136,233,34,3,223,208,241,192,3, +135,227,224,127,196,2,87,132,17,82,143,24,10,44,96,36,240,4,147,64,146,119, +4,125,49,131,52,152,65,154,128,0,201,97,9,36,133,36,142,25,18,40,114,77,98, +17,33,137,68,130,45,17,247,240,71,159,193,29,127,8,0,12,113,252,32,0,49, +184,208,70,162,144,20,95,240,0,7,252,80,37,120,193,81,196,194,0,3,69,19,0, +81,191,197,140,192,255,255,239,127,255,255,255,255,140,64,0,0,0,0,1,0,0,0, +139,192,0,0,248,127,0,0,0,0,138,192,0,0,240,127,0,0,0,0,139,64,0,0,240,255, +0,0,0,0,0,31,241,128,149,224,0,0,0,0,0,0,0,0,13,71,98,37,25,128,148,86,48, +69,23,201,19,94,36,73,132,129,71,255,0,56,136,233,34,3,223,208,241,192,3, 254,56,18,188,128,0,15,135,240,0,0,0,11,104,228,128,135,18,4,0,6,26,72,16, 0,42,49,32,64,0,225,132,129,0,4,133,146,4,0,21,210,72,16,0,103,65,32,64,1, 220,228,100,162,146,130,20,74,8,72,248,64,2,33,3,225,0,9,131,143,132,0,42, @@ -13237,9 +13094,9 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { 33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0, 133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92, 195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225, -132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,240,71,19,201,40, -239,64,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,137,129,109,203,140, -11,78,94,96,13,28,200,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47, +132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40, +239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139, +203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47, 252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183, 54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127, 206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15, @@ -13247,126 +13104,51 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = { 110,218,208,16,139,185,143,251,206,126,191,154,176,17,197,125,207,255,160, 138,217,90,144,30,242,246,207,195,185,73,133,90,112,62,200,66,80,6,11,81, 21,26,80,39,168,57,143,243,78,223,217,154,48,39,168,61,143,243,78,223,217, -146,104,39,17,158,156,80,0,22,114,113,64,0,153,169,197,0,3,102,40,33,150, -156,80,0,70,82,113,64,1,89,41,197,0,6,100,39,20,0,29,142,156,80,0,134,50, -98,243,21,53,121,136,160,144,0,22,26,120,24,73,197,0,9,96,167,20,0,41,128, -156,80,0,181,250,113,64,3,1,255,254,0,81,20,100,47,145,216,23,255,240,0,11, -255,248,0,3,255,252,81,252,8,4,252,68,0,0,0,0,0,129,167,1,26,144,9,165,0, -26,177,199,197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52, -39,32,84,223,192,15,59,30,129,156,115,6,81,160,7,253,40,0,5,81,252,0,1,255, -78,0,84,113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,66,0,3,69, -117,0,85,159,192,0,31,245,97,10,100,0,0,0,32,0,0,0,0,10,164,130,97,221,191, -113,3,20,146,12,18,200,47,74,30,23,37,15,128,0,143,146,135,192,0,133,169, -67,224,0,98,196,161,240,0,65,90,80,248,0,41,63,255,194,109,65,11,137,191, -174,45,153,98,242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188, -185,111,228,131,70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255, -174,0,25,168,194,64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233, -0,32,54,139,164,0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139, -164,0,140,208,46,144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200, -50,208,2,19,24,203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64, -127,255,128,21,38,73,7,1,132,128,0,133,105,252,19,140,0,0,15,3,240,0,0,0,0, -25,127,102,0,1,91,127,4,227,0,0,3,192,252,0,0,0,0,6,95,218,128,0,87,31,193, -56,192,0,0,240,63,0,0,0,0,1,151,246,224,0,21,215,240,78,48,0,0,0,16,0,0,0, -0,0,101,253,200,0,5,121,252,19,140,0,0,0,4,0,0,0,0,0,25,127,118,0,1,95,127, -4,227,0,0,0,65,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,0,0,16,64,0,0,0,0, -1,151,247,224,0,22,23,240,78,48,0,0,4,16,0,0,0,0,0,101,254,8,0,5,137,252, -19,140,0,0,2,4,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,146,20,74,228,80, -171,17,64,162,132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32, -152,23,72,0,10,92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18, -76,93,32,1,73,33,116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104, -225,116,128,2,35,69,210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128, -10,162,69,218,0,58,136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18, -132,25,104,0,138,12,101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0, -145,252,101,160,3,71,225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101, -160,1,135,161,152,128,2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180, -117,150,57,214,0,157,85,98,112,80,137,241,66,128,0,166,213,33,53,24,66,121, -106,0, +146,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160, +80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243, +21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0, +181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0, +3,255,252,81,252,8,4,252,68,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199, +197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84, +223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84, +113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85, +159,192,0,31,245,97,10,100,0,0,0,32,0,0,0,0,10,164,130,97,221,191,113,3,20, +178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98, +196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98, +242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131, +70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194, +64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164, +0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46, +144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24, +203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21, +38,81,7,1,132,128,0,133,105,252,19,140,0,0,15,3,240,0,0,0,0,25,127,102,0,1, +91,127,4,227,0,0,3,192,252,0,0,0,0,6,95,218,128,0,87,31,193,56,192,0,0,240, +63,0,0,0,0,1,151,246,224,0,21,215,240,78,48,0,0,0,16,0,0,0,0,0,101,253,200, +0,5,121,252,19,140,0,0,0,4,0,0,0,0,0,25,127,118,0,1,95,127,4,227,0,0,0,65, +0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,0,0,16,64,0,0,0,0,1,151,247,224, +0,22,23,240,78,48,0,0,4,16,0,0,0,0,0,101,254,8,0,5,137,252,19,140,0,0,2,4, +0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132, +248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93, +32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116, +128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210, +0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25, +98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160, +3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150, +128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158, +70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98, +112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0, }; #ifdef DUK_USE_BUILTIN_INITJS -DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = { -47,42,10,32,42,32,32,73,110,105,116,32,99,111,100,101,32,102,111,114,32, -108,101,103,97,99,121,32,99,111,109,112,97,116,105,98,105,108,105,116,121, -46,10,32,42,10,32,42,32,32,67,111,109,112,97,116,105,98,105,108,105,116, -121,32,112,114,111,112,101,114,116,105,101,115,32,47,32,119,114,97,112,112, -101,114,32,102,117,110,99,116,105,111,110,115,32,104,101,114,101,32,97,108, -108,111,119,32,68,117,107,116,97,112,101,32,116,111,32,114,101,109,97,105, -110,10,32,42,32,32,99,111,109,112,97,116,105,98,108,101,32,102,111,114,32, -117,115,101,114,32,99,111,100,101,32,119,104,101,110,32,99,111,114,101,32, -102,101,97,116,117,114,101,115,32,97,114,101,32,99,104,97,110,103,101,100, -44,32,119,105,116,104,111,117,116,32,98,117,114,100,101,110,105,110,103,10, -32,42,32,32,116,104,101,32,109,97,105,110,32,67,32,99,111,100,101,32,119, -105,116,104,32,99,111,109,112,97,116,105,98,105,108,105,116,121,32,115,116, -117,102,102,46,10,32,42,10,32,42,32,32,84,104,105,115,32,102,105,108,101, -32,105,115,32,109,105,110,105,102,105,101,100,32,119,105,116,104,32,85,103, -108,105,102,121,74,83,32,111,114,32,116,104,101,32,99,108,111,115,117,114, -101,32,99,111,109,112,105,108,101,114,46,32,32,66,111,116,104,32,119,105, -108,108,10,32,42,32,32,114,101,110,97,109,101,32,118,97,114,105,97,98,108, -101,115,44,32,114,101,109,111,118,101,32,99,111,109,109,101,110,116,115,44, -32,97,110,100,32,97,114,101,32,99,108,101,118,101,114,32,101,110,111,117, -103,104,32,116,111,32,100,114,111,112,32,97,110,121,10,32,42,32,32,34,105, -102,32,40,102,97,108,115,101,41,32,123,32,46,46,46,32,125,34,32,98,108,111, -99,107,115,32,97,108,116,111,103,101,116,104,101,114,44,32,115,111,32,116, -104,97,116,39,115,32,97,110,32,101,102,102,101,99,116,105,118,101,32,119, -97,121,32,116,111,10,32,42,32,32,100,105,115,97,98,108,101,32,99,117,114, -114,101,110,116,108,121,32,117,110,110,101,101,100,101,100,32,99,111,100, -101,46,10,32,42,47,10,10,40,102,117,110,99,116,105,111,110,40,71,44,32,68, -41,32,123,10,32,32,32,32,39,117,115,101,32,115,116,114,105,99,116,39,59,10, -10,32,32,32,32,102,117,110,99,116,105,111,110,32,100,101,102,40,111,98,106, -101,99,116,44,32,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32, -32,32,32,32,32,32,32,79,98,106,101,99,116,46,100,101,102,105,110,101,80, -114,111,112,101,114,116,121,40,111,98,106,101,99,116,44,32,110,97,109,101, -44,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,118,97,108,117,101,58,32, -118,97,108,117,101,44,10,32,32,32,32,32,32,32,32,32,32,32,32,119,114,105, -116,97,98,108,101,58,32,116,114,117,101,44,10,32,32,32,32,32,32,32,32,32, -32,32,32,101,110,117,109,101,114,97,98,108,101,58,32,102,97,108,115,101,44, -10,32,32,32,32,32,32,32,32,32,32,32,32,99,111,110,102,105,103,117,114,97, -98,108,101,58,32,116,114,117,101,10,32,32,32,32,32,32,32,32,125,41,59,10, -32,32,32,32,125,10,10,32,32,32,32,102,117,110,99,116,105,111,110,32,100, -101,102,68,40,110,97,109,101,44,32,118,97,108,117,101,41,32,123,10,32,32, -32,32,32,32,32,32,100,101,102,40,68,44,32,110,97,109,101,44,32,118,97,108, -117,101,41,59,10,32,32,32,32,125,10,10,32,32,32,32,47,47,32,67,111,109,112, -97,116,105,98,105,108,105,116,121,32,102,111,114,32,39,99,111,110,115,111, -108,101,46,108,111,103,39,46,10,32,32,32,32,105,102,32,40,102,97,108,115, -101,41,32,123,10,32,32,32,32,32,32,32,32,99,111,110,115,111,108,101,32,61, -32,123,10,32,32,32,32,32,32,32,32,32,32,32,32,108,111,103,58,32,102,117, -110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,32,32,32,32, -32,32,32,32,112,114,105,110,116,40,65,114,114,97,121,46,112,114,111,116, -111,116,121,112,101,46,106,111,105,110,46,99,97,108,108,40,97,114,103,117, -109,101,110,116,115,44,32,39,32,39,41,41,59,10,32,32,32,32,32,32,32,32,32, -32,32,32,125,10,32,32,32,32,32,32,32,32,125,59,10,32,32,32,32,125,10,10,32, -32,32,32,47,47,32,68,117,107,116,97,112,101,46,108,105,110,101,40,41,32, -119,97,115,32,114,101,109,111,118,101,100,32,105,110,32,68,117,107,116,97, -112,101,32,48,46,49,49,46,48,44,32,104,101,114,101,39,115,32,97,110,32,101, -120,97,109,112,108,101,10,32,32,32,32,47,47,32,114,101,112,108,97,99,101, -109,101,110,116,32,117,115,101,114,32,99,111,100,101,32,99,111,117,108,100, -32,117,115,101,46,10,32,32,32,32,105,102,32,40,102,97,108,115,101,41,32, -123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,108,105,110,101, -39,44,32,102,117,110,99,116,105,111,110,32,40,41,32,123,10,32,32,32,32,32, -32,32,32,32,32,32,32,39,117,115,101,32,100,117,107,32,110,111,116,97,105, -108,39,59,10,10,32,32,32,32,32,32,32,32,32,32,32,32,47,42,32,84,97,105,108, -32,99,97,108,108,115,32,97,114,101,32,112,114,101,118,101,110,116,101,100, -32,116,111,32,101,110,115,117,114,101,32,99,97,108,108,105,110,103,32,97, -99,116,105,118,97,116,105,111,110,32,101,120,105,115,116,115,46,10,32,32, -32,32,32,32,32,32,32,32,32,32,32,42,32,67,97,108,108,32,115,116,97,99,107, -32,105,110,100,105,99,101,115,58,32,45,49,32,61,32,68,117,107,116,97,112, -101,46,97,99,116,44,32,45,50,32,61,32,103,101,116,67,117,114,114,101,110, -116,76,105,110,101,44,32,45,51,32,61,32,99,97,108,108,101,114,10,32,32,32, -32,32,32,32,32,32,32,32,32,32,42,47,10,10,32,32,32,32,32,32,32,32,32,32,32, -32,114,101,116,117,114,110,32,40,68,117,107,116,97,112,101,46,97,99,116,40, -45,51,41,32,124,124,32,123,125,41,46,108,105,110,101,78,117,109,98,101,114, -59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,10,10,32,32,32, -32,47,47,32,76,111,103,103,101,114,32,111,98,106,101,99,116,32,102,111,114, -32,67,32,99,111,100,101,32,112,114,111,118,105,100,101,100,32,98,121,32, -105,110,105,116,32,99,111,100,101,32,110,111,119,46,10,32,32,32,32,105,102, -32,40,116,114,117,101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40, -68,46,76,111,103,103,101,114,44,32,39,99,108,111,103,39,44,32,110,101,119, -32,68,46,76,111,103,103,101,114,40,39,67,39,41,41,59,10,32,32,32,32,125,10, -10,32,32,32,32,47,47,32,84,114,97,99,107,105,110,103,32,116,97,98,108,101, -32,102,111,114,32,67,111,109,109,111,110,74,83,32,109,111,100,117,108,101, -32,108,111,97,100,105,110,103,46,10,32,32,32,32,105,102,32,40,116,114,117, -101,41,32,123,10,32,32,32,32,32,32,32,32,100,101,102,40,68,44,32,39,109, -111,100,76,111,97,100,101,100,39,44,32,123,125,41,59,10,32,32,32,32,125,10, -125,41,40,116,104,105,115,44,32,68,117,107,116,97,112,101,41,59,10,0, +DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = { +40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116, +105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101, +102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97, +108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117, +109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98, +108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99, +108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34, +41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,123,125,41, +125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,59,10,0, }; #endif /* DUK_USE_BUILTIN_INITJS */ #else @@ -13381,9 +13163,9 @@ DUK_INTERNAL const duk_uint8_t duk_initjs_data[1757] = { #define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */ -#ifdef DUK_USE_VERBOSE_ERRORS +#if defined(DUK_USE_VERBOSE_ERRORS) -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) DUK_INTERNAL void duk_err_handle_error(const char *filename, duk_int_t line, duk_hthread *thr, duk_errcode_t code, const char *fmt, ...) { va_list ap; char msg[DUK__ERRFMT_BUFSIZE]; @@ -13423,7 +13205,7 @@ DUK_INTERNAL void duk_err_handle_error_stash(duk_hthread *thr, duk_errcode_t cod #else /* DUK_USE_VERBOSE_ERRORS */ -#ifdef DUK_USE_VARIADIC_MACROS +#if defined(DUK_USE_VARIADIC_MACROS) DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { duk_err_create_and_throw(thr, code); } @@ -13444,13 +13226,50 @@ DUK_INTERNAL void duk_err_handle_error_nonverbose2(const char *filename, duk_int #endif /* DUK_USE_VERBOSE_ERRORS */ +/* + * Error throwing helpers + */ + +#if defined(DUK_USE_VERBOSE_ERRORS) +#if defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name) { + DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", + expect_name, duk_get_type_name((duk_context *) thr, index), (long) index); +} +#else +DUK_INTERNAL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index, const char *expect_name) { + DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)", + expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index); +} +#endif +DUK_INTERNAL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, duk_idx_t index) { + DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index)); +} +DUK_INTERNAL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message) { + DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_API_ERROR, message); +} +#else +DUK_INTERNAL void duk_err_require_type_index(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message) { + DUK_UNREF(filename); DUK_UNREF(linenumber); DUK_UNREF(message); + DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_TYPE_ERROR, message); +} +DUK_INTERNAL void duk_err_api_index(const char *filename, duk_int_t linenumber, duk_hthread *thr) { + DUK_UNREF(filename); DUK_UNREF(linenumber); + DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX); +} +DUK_INTERNAL void duk_err_api(const char *filename, duk_int_t linenumber, duk_hthread *thr, const char *message) { + DUK_UNREF(filename); DUK_UNREF(linenumber); DUK_UNREF(message); + DUK_ERROR_RAW(filename, linenumber, thr, DUK_ERR_API_ERROR, message); +} +#endif + /* * Default fatal error handler */ DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) { DUK_UNREF(ctx); -#ifdef DUK_USE_FILE_IO +#if defined(DUK_USE_FILE_IO) DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null")); DUK_FFLUSH(DUK_STDERR); #else @@ -13467,7 +13286,7 @@ DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code #if !defined(DUK_USE_PANIC_HANDLER) DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) { -#ifdef DUK_USE_FILE_IO +#if defined(DUK_USE_FILE_IO) DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s (" #if defined(DUK_USE_PANIC_ABORT) "calling abort" @@ -13760,26 +13579,117 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, return 0; } -/* (extended) utf-8 length without codepoint encoding validation, used - * for string interning (should probably be inlined). +/* Compute (extended) utf-8 length without codepoint encoding validation, + * used for string interning. + * + * NOTE: This algorithm is performance critical, more so than string hashing + * in some cases. It is needed when interning a string and needs to scan + * every byte of the string with no skipping. Having an ASCII fast path + * is useful if possible in the algorithm. The current algorithms were + * chosen from several variants, based on x64 gcc -O2 testing. See: + * https://github.com/svaarala/duktape/pull/422 + */ + +#if defined(DUK_USE_PREFER_SIZE) +/* Small variant; roughly 150 bytes smaller than the fast variant. */ +DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { + const duk_uint8_t *p; + const duk_uint8_t *p_end; + duk_size_t ncont; + duk_size_t clen; + + p = data; + p_end = data + blen; + ncont = 0; + while (p != p_end) { + duk_uint8_t x; + x = *p++; + if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { + ncont++; + } + } + + DUK_ASSERT(ncont <= blen); + clen = blen - ncont; + DUK_ASSERT(clen <= blen); + return clen; +} +#else /* DUK_USE_PREFER_SIZE */ +/* This seems like a good overall approach. Fast path for ASCII in 4 byte + * blocks. */ DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { - const duk_uint8_t *p = data; - const duk_uint8_t *p_end = data + blen; - duk_size_t clen = 0; + const duk_uint8_t *p; + const duk_uint8_t *p_end; + const duk_uint32_t *p32_end; + const duk_uint32_t *p32; + duk_size_t ncont; + duk_size_t clen; - while (p < p_end) { - duk_uint8_t x = *p++; - if (x < 0x80 || x >= 0xc0) { - /* 10xxxxxx = continuation chars (0x80...0xbf), above - * and below that initial bytes. + ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */ + p = data; + p_end = data + blen; + if (blen < 16) { + goto skip_fastpath; + } + + /* Align 'p' to 4; the input data may have arbitrary alignment. + * End of string check not needed because blen >= 16. + */ + while (((duk_uintptr_t) (const void *) p) & 0x03) { + duk_uint8_t x; + x = *p++; + if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { + ncont++; + } + } + + /* Full, aligned 4-byte reads. */ + p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03))); + p32 = (const duk_uint32_t *) (const void *) p; + while (p32 != (const duk_uint32_t *) p32_end) { + duk_uint32_t x; + x = *p32++; + if (DUK_LIKELY((x & 0x80808080UL) == 0)) { + ; /* ASCII fast path */ + } else { + /* Flip highest bit of each byte which changes + * the bit pattern 10xxxxxx into 00xxxxxx which + * allows an easy bit mask test. */ - clen++; + x ^= 0x80808080UL; + if (DUK_UNLIKELY(!(x & 0xc0000000UL))) { + ncont++; + } + if (DUK_UNLIKELY(!(x & 0x00c00000UL))) { + ncont++; + } + if (DUK_UNLIKELY(!(x & 0x0000c000UL))) { + ncont++; + } + if (DUK_UNLIKELY(!(x & 0x000000c0UL))) { + ncont++; + } + } + } + p = (const duk_uint8_t *) p32; + /* Fall through to handle the rest. */ + + skip_fastpath: + while (p != p_end) { + duk_uint8_t x; + x = *p++; + if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { + ncont++; } } + DUK_ASSERT(ncont <= blen); + clen = blen - ncont; + DUK_ASSERT(clen <= blen); return clen; } +#endif /* DUK_USE_PREFER_SIZE */ /* * Unicode range matcher @@ -13814,7 +13724,7 @@ DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_si duk_codepoint_t prev_re; DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); - bd_ctx.data = (duk_uint8_t *) unitab; + bd_ctx.data = (const duk_uint8_t *) unitab; bd_ctx.length = (duk_size_t) unilen; prev_re = 0; @@ -14359,10 +14269,10 @@ duk_codepoint_t duk__case_transform_helper(duk_hthread *thr, /* 1:1 or special conversions, but not locale/context specific: script generated rules */ DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); if (uppercase) { - bd_ctx.data = (duk_uint8_t *) duk_unicode_caseconv_uc; + bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc; bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc); } else { - bd_ctx.data = (duk_uint8_t *) duk_unicode_caseconv_lc; + bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc; bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc); } return duk__slow_case_conversion(thr, bw, cp, &bd_ctx); @@ -14400,7 +14310,7 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in /* [ ... input buffer ] */ - p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); p = p_start; @@ -14453,14 +14363,15 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in */ DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) { -#if 1 /* FIXME */ +#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) /* Fast canonicalization lookup at the cost of 128kB footprint. */ DUK_ASSERT(cp >= 0); + DUK_UNREF(thr); if (DUK_LIKELY(cp < 0x10000L)) { return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp]; } return cp; -#else +#else /* DUK_USE_REGEXP_CANON_WORKAROUND */ duk_codepoint_t y; y = duk__case_transform_helper(thr, @@ -14478,7 +14389,7 @@ DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, } return y; -#endif +#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */ } /* @@ -14566,24 +14477,31 @@ DUK_INTERNAL duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = { * hex nybble table. */ -DUK_INTERNAL duk_uint8_t duk_lc_digits[36] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z' +DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = { + DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, + DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, + DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B, + DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F, + DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J, + DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N, + DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R, + DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V, + DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z }; -DUK_INTERNAL duk_uint8_t duk_uc_nybbles[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = { + DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, + DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, + DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B, + DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F }; /* - * Table for decoding ASCII hex digits, -1 if invalid. + * Table for hex decoding ASCII hex digits */ -DUK_INTERNAL duk_int8_t duk_hex_dectab[256] = { +DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = { + /* -1 if invalid */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ @@ -14602,6 +14520,154 @@ DUK_INTERNAL duk_int8_t duk_hex_dectab[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ }; +#if defined(DUK_USE_HEX_FASTPATH) +/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */ +DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */ + -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */ + -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ +}; +#endif + +/* + * Table for hex encoding bytes + */ + +#if defined(DUK_USE_HEX_FASTPATH) +/* Lookup to encode one byte directly into 2 characters: + * + * def genhextab(bswap): + * for i in xrange(256): + * t = chr(i).encode('hex') + * if bswap: + * t = t[1] + t[0] + * print('0x' + t.encode('hex') + 'U') + * print('big endian'); genhextab(False) + * print('little endian'); genhextab(True) +*/ +DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = { +#if defined(DUK_USE_INTEGER_BE) + 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U, + 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U, + 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U, + 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U, + 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U, + 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U, + 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U, + 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U, + 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U, + 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U, + 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U, + 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U, + 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U, + 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U, + 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U, + 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U, + 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U, + 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U, + 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U, + 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U, + 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U, + 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U, + 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U, + 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U, + 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U, + 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U, + 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U, + 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U, + 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U, + 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U, + 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U, + 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U +#else /* DUK_USE_INTEGER_BE */ + 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U, + 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U, + 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U, + 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U, + 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U, + 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U, + 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U, + 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U, + 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U, + 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U, + 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U, + 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U, + 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U, + 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U, + 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U, + 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U, + 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U, + 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U, + 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U, + 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U, + 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U, + 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U, + 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U, + 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U, + 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U, + 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U, + 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U, + 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U, + 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U, + 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U, + 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U, + 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U +#endif /* DUK_USE_INTEGER_BE */ +}; +#endif /* DUK_USE_HEX_FASTPATH */ + +/* + * Table for base-64 encoding + */ + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = { + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */ + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */ + 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */ + 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */ +}; +#endif /* DUK_USE_BASE64_FASTPATH */ + +/* + * Table for base-64 decoding + */ + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = { + /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */ + -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */ + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */ + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */ +}; +#endif /* DUK_USE_BASE64_FASTPATH */ + /* * Arbitrary byteswap for potentially unaligned values * @@ -16216,18 +16282,89 @@ DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t mag * Encoding and decoding basic formats: hex, base64. * * These are in-place operations which may allow an optimized implementation. + * + * Base-64: https://tools.ietf.org/html/rfc4648#section-4 */ /* include removed: duk_internal.h */ -/* dst length must be exactly ceil(len/3)*4 */ -DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, const duk_uint8_t *src_end, - duk_uint8_t *dst, duk_uint8_t *dst_end) { +/* Shared handling for encode/decode argument. Fast path handling for + * buffer and string values because they're the most common. In particular, + * avoid creating a temporary string or buffer when possible. + */ +DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { + DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */ + if (duk_is_buffer(ctx, index)) { + return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len); + } else { + return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len); + } +} + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { + duk_uint_t t; + duk_size_t n_full, n_full3, n_final; + const duk_uint8_t *src_end_fast; + + n_full = srclen / 3; /* full 3-byte -> 4-char conversions */ + n_full3 = n_full * 3; + n_final = srclen - n_full3; + DUK_ASSERT_DISABLE(n_final >= 0); + DUK_ASSERT(n_final <= 2); + + src_end_fast = src + n_full3; + while (DUK_UNLIKELY(src != src_end_fast)) { + t = (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + + *dst++ = duk_base64_enctab[t >> 18]; + *dst++ = duk_base64_enctab[(t >> 12) & 0x3f]; + *dst++ = duk_base64_enctab[(t >> 6) & 0x3f]; + *dst++ = duk_base64_enctab[t & 0x3f]; + +#if 0 /* Tested: not faster on x64 */ + /* aaaaaabb bbbbcccc ccdddddd */ + dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f]; + dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)]; + dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)]; + dst[3] = duk_base64_enctab[src[2] & 0x3f]; + src += 3; dst += 4; +#endif + } + + switch (n_final) { + /* case 0: nop */ + case 1: { + /* XX== */ + t = (duk_uint_t) (*src++); + *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */ + *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */ + *dst++ = DUK_ASC_EQUALS; + *dst++ = DUK_ASC_EQUALS; + break; + } + case 2: { + /* XXX= */ + t = (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */ + *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */ + *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */ + *dst++ = DUK_ASC_EQUALS; + break; + } + } +} +#else /* DUK_USE_BASE64_FASTPATH */ +DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { duk_small_uint_t i, snip; - duk_uint_fast32_t t; + duk_uint_t t; duk_uint_fast8_t x, y; + const duk_uint8_t *src_end; - DUK_UNREF(dst_end); + src_end = src + srclen; while (src < src_end) { /* read 3 bytes into 't', padded by zero */ @@ -16238,7 +16375,7 @@ DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, const duk_uint8 if (src >= src_end) { snip--; } else { - t += (duk_uint_fast32_t) (*src++); + t += (duk_uint_t) (*src++); } } @@ -16272,22 +16409,159 @@ DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, const duk_uint8 y = '/'; } - DUK_ASSERT(dst < dst_end); *dst++ = (duk_uint8_t) y; } } } +#endif /* DUK_USE_BASE64_FASTPATH */ -DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk_uint8_t *src_end, - duk_uint8_t *dst, duk_uint8_t *dst_end, duk_uint8_t **out_dst_final) { - duk_uint_fast32_t t; +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { + duk_int_t x; + duk_int_t t; + duk_small_uint_t n_equal; + duk_small_uint_t n_chars; + const duk_uint8_t *src_end; + const duk_uint8_t *src_end_safe; + + src_end = src + srclen; + src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */ + + /* Innermost fast path processes 4 valid base-64 characters at a time + * but bails out on whitespace, padding chars ('=') and invalid chars. + * Once the slow path segment has been processed, we return to the + * inner fast path again. This handles e.g. base64 with newlines + * reasonably well because the majority of a line is in the fast path. + */ + for (;;) { + /* Fast path, handle units with just actual encoding characters. */ + + while (src <= src_end_safe) { + /* The lookup byte is intentionally sign extended to (at least) + * 32 bits and then ORed. This ensures that is at least 1 byte + * is negative, the highest bit of 't' will be set at the end + * and we don't need to check every byte. + */ + DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p", + (const void *) src, (const void *) src_end_safe, (const void *) src_end)); + + t = (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + + if (DUK_UNLIKELY(t < 0)) { + DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit")); + src -= 4; + break; + } + + DUK_ASSERT(t <= 0xffffffL); + DUK_ASSERT((t >> 24) == 0); + *dst++ = (duk_uint8_t) (t >> 16); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + } + + /* Handle one slow path unit (or finish if we're done). */ + + n_equal = 0; + n_chars = 0; + t = 0; + for (;;) { + DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld", + (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t)); + + if (DUK_UNLIKELY(src >= src_end)) { + goto done; /* two level break */ + } + + x = duk_base64_dectab[*src++]; + if (DUK_UNLIKELY(x < 0)) { + if (x == -2) { + continue; /* allowed ascii whitespace */ + } else if (x == -3) { + n_equal++; + t <<= 6; + } else { + DUK_ASSERT(x == -1); + goto error; + } + } else { + DUK_ASSERT(x >= 0 && x <= 63); + if (n_equal > 0) { + /* Don't allow actual chars after equal sign. */ + goto error; + } + t = (t << 6) + x; + } + + if (DUK_UNLIKELY(n_chars == 3)) { + /* Emit 3 bytes and backtrack if there was padding. There's + * always space for the whole 3 bytes so no check needed. + */ + DUK_ASSERT(t <= 0xffffffL); + DUK_ASSERT((t >> 24) == 0); + *dst++ = (duk_uint8_t) (t >> 16); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + + if (DUK_UNLIKELY(n_equal > 0)) { + DUK_ASSERT(n_equal <= 4); + + /* There may be whitespace between the equal signs. */ + if (n_equal == 1) { + /* XXX= */ + dst -= 1; + } else if (n_equal == 2) { + /* XX== */ + dst -= 2; + } else { + goto error; /* invalid padding */ + } + + /* Continue parsing after padding, allows concatenated, + * padded base64. + */ + } + break; /* back to fast loop */ + } else { + n_chars++; + } + } + } + done: + DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld", + (const void *) src, (const void *) src_end, (long) n_chars)); + + DUK_ASSERT(src == src_end); + + if (n_chars != 0) { + /* Here we'd have the option of decoding unpadded base64 + * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not + * accepted. + */ + goto error; + } + + *out_dst_final = dst; + return 1; + + error: + return 0; +} +#else /* DUK_USE_BASE64_FASTPATH */ +DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { + duk_uint_t t; duk_uint_fast8_t x, y; duk_small_uint_t group_idx; + duk_small_uint_t n_equal; + const duk_uint8_t *src_end; - DUK_UNREF(dst_end); - + src_end = src + srclen; t = 0; group_idx = 0; + n_equal = 0; while (src < src_end) { x = *src++; @@ -16303,42 +16577,14 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk } else if (x == '/') { y = 63; } else if (x == '=') { - /* We don't check the zero padding bytes here right now. - * This seems to be common behavior for base-64 decoders. + /* We don't check the zero padding bytes here right now + * (that they're actually zero). This seems to be common + * behavior for base-64 decoders. */ - if (group_idx == 2) { - /* xx== -> 1 byte, t contains 12 bits, 4 on right are zero */ - t = t >> 4; - DUK_ASSERT(dst < dst_end); - *dst++ = (duk_uint8_t) t; - - if (src >= src_end) { - goto error; - } - x = *src++; - if (x != '=') { - goto error; - } - } else if (group_idx == 3) { - /* xxx= -> 2 bytes, t contains 18 bits, 2 on right are zero */ - t = t >> 2; - DUK_ASSERT(dst < dst_end); - *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - DUK_ASSERT(dst < dst_end); - *dst++ = (duk_uint8_t) (t & 0xff); - } else { - goto error; - } - - /* Here we can choose either to end parsing and ignore - * whatever follows, or to continue parsing in case - * multiple (possibly padded) base64 strings have been - * concatenated. Currently, keep on parsing. - */ - t = 0; - group_idx = 0; - continue; + n_equal++; + t <<= 6; /* shift in zeroes */ + goto skip_add; } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) { /* allow basic ASCII whitespace */ continue; @@ -16346,16 +16592,38 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk goto error; } + if (n_equal > 0) { + /* Don't allow mixed padding and actual chars. */ + goto error; + } t = (t << 6) + y; + skip_add: if (group_idx == 3) { /* output 3 bytes from 't' */ - DUK_ASSERT(dst < dst_end); *dst++ = (duk_uint8_t) ((t >> 16) & 0xff); - DUK_ASSERT(dst < dst_end); *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); - DUK_ASSERT(dst < dst_end); *dst++ = (duk_uint8_t) (t & 0xff); + + if (DUK_UNLIKELY(n_equal > 0)) { + /* Backtrack. */ + DUK_ASSERT(n_equal <= 4); + if (n_equal == 1) { + dst -= 1; + } else if (n_equal == 2) { + dst -= 2; + } else { + goto error; /* invalid padding */ + } + + /* Here we can choose either to end parsing and ignore + * whatever follows, or to continue parsing in case + * multiple (possibly padded) base64 strings have been + * concatenated. Currently, keep on parsing. + */ + n_equal = 0; + } + t = 0; group_idx = 0; } else { @@ -16377,23 +16645,11 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, const duk error: return 0; } - -/* Shared handling for encode/decode argument. Fast path handling for - * buffer and string values because they're the most common. In particular, - * avoid creating a temporary string or buffer when possible. - */ -DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { - DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */ - if (duk_is_buffer(ctx, index)) { - return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len); - } else { - return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len); - } -} +#endif /* DUK_USE_BASE64_FASTPATH */ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { duk_hthread *thr = (duk_hthread *) ctx; - duk_uint8_t *src; + const duk_uint8_t *src; duk_size_t srclen; duk_size_t dstlen; duk_uint8_t *dst; @@ -16406,7 +16662,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { */ index = duk_require_normalize_index(ctx, index); - src = (duk_uint8_t *) duk_to_buffer(ctx, index, &srclen); + src = duk__prep_codec_arg(ctx, index, &srclen); /* Note: for srclen=0, src may be NULL */ /* Computation must not wrap; this limit works for 32-bit size_t: @@ -16420,8 +16676,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { dstlen = (srclen + 2) / 3 * 4; dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen); - duk__base64_encode_helper((const duk_uint8_t *) src, (const duk_uint8_t *) (src + srclen), - dst, (dst + dstlen)); + duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst); ret = duk_to_string(ctx, -1); duk_replace(ctx, index); @@ -16448,7 +16703,7 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) { */ index = duk_require_normalize_index(ctx, index); - src = (const duk_uint8_t *) duk_to_lstring(ctx, index, &srclen); + src = duk__prep_codec_arg(ctx, index, &srclen); /* Computation must not wrap, only srclen + 3 is at risk of * wrapping because after that the number gets smaller. @@ -16458,12 +16713,11 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) { if (srclen > 4294967292UL) { goto type_error; } - dstlen = (srclen + 3) / 4 * 3; /* upper limit */ + dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */ dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen); /* Note: for dstlen=0, dst may be NULL */ - retval = duk__base64_decode_helper((const duk_uint8_t *) src, (const duk_uint8_t *) (src + srclen), - dst, dst + dstlen, &dst_final); + retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final); if (!retval) { goto type_error; } @@ -16481,9 +16735,12 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) { const duk_uint8_t *inp; duk_size_t len; duk_size_t i; - duk_small_uint_t t; duk_uint8_t *buf; const char *ret; +#if defined(DUK_USE_HEX_FASTPATH) + duk_size_t len_safe; + duk_uint16_t *p16; +#endif DUK_ASSERT_CTX_VALID(ctx); @@ -16495,12 +16752,28 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) { buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/); DUK_ASSERT(buf != NULL); +#if defined(DUK_USE_HEX_FASTPATH) + DUK_ASSERT((((duk_uintptr_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */ + p16 = (duk_uint16_t *) (void *) buf; + len_safe = len & ~0x03U; + for (i = 0; i < len_safe; i += 4) { + p16[0] = duk_hex_enctab[inp[i]]; + p16[1] = duk_hex_enctab[inp[i + 1]]; + p16[2] = duk_hex_enctab[inp[i + 2]]; + p16[3] = duk_hex_enctab[inp[i + 3]]; + p16 += 4; + } + for (; i < len; i++) { + *p16++ = duk_hex_enctab[inp[i]]; + } +#else /* DUK_USE_HEX_FASTPATH */ for (i = 0; i < len; i++) { - /* XXX: by using two 256-entry tables could avoid shifting and masking. */ + duk_small_uint_t t; t = (duk_small_uint_t) inp[i]; buf[i*2 + 0] = duk_lc_digits[t >> 4]; buf[i*2 + 1] = duk_lc_digits[t & 0x0f]; } +#endif /* DUK_USE_HEX_FASTPATH */ /* XXX: Using a string return value forces a string intern which is * not always necessary. As a rough performance measure, hex encode @@ -16519,8 +16792,13 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { const duk_uint8_t *inp; duk_size_t len; duk_size_t i; - duk_small_int_t t; + duk_int_t t; duk_uint8_t *buf; +#if defined(DUK_USE_HEX_FASTPATH) + duk_int_t chk; + duk_uint8_t *p; + duk_size_t len_safe; +#endif DUK_ASSERT_CTX_VALID(ctx); @@ -16536,18 +16814,55 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/); DUK_ASSERT(buf != NULL); +#if defined(DUK_USE_HEX_FASTPATH) + p = buf; + len_safe = len & ~0x07U; + for (i = 0; i < len_safe; i += 8) { + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + chk = t; + p[0] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 3]]); + chk |= t; + p[1] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 5]]); + chk |= t; + p[2] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 7]]); + chk |= t; + p[3] = (duk_uint8_t) t; + p += 4; + + /* Check if any lookup above had a negative result. */ + if (DUK_UNLIKELY(chk < 0)) { + goto type_error; + } + } + for (; i < len; i += 2) { + t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + if (DUK_UNLIKELY(t < 0)) { + goto type_error; + } + *p++ = (duk_uint8_t) t; + } +#else /* DUK_USE_HEX_FASTPATH */ for (i = 0; i < len; i += 2) { /* For invalid characters the value -1 gets extended to * at least 16 bits. If either nybble is invalid, the * resulting 't' will be < 0. */ - t = (((duk_small_int_t) duk_hex_dectab[inp[i]]) << 4) | - ((duk_small_int_t) duk_hex_dectab[inp[i + 1]]); + t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); if (DUK_UNLIKELY(t < 0)) { goto type_error; } buf[i >> 1] = (duk_uint8_t) t; } +#endif /* DUK_USE_HEX_FASTPATH */ duk_replace(ctx, index); return; @@ -16696,7 +17011,7 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) { * file given to duk_peval_file() or similar, the * error message is not the best possible. */ - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_NO_SOURCECODE); + DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE); } DUK_ASSERT(h_sourcecode != NULL); comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode); @@ -16838,6 +17153,10 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx, const char *str; duk_size_t len; + /* XXX: should there be an error or an automatic detach if + * already attached? + */ + DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(read_cb != NULL); DUK_ASSERT(write_cb != NULL); @@ -16851,6 +17170,7 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx, heap->dbg_write_flush_cb = write_flush_cb; heap->dbg_detached_cb = detached_cb; heap->dbg_udata = udata; + heap->dbg_have_next_byte = 0; /* Start in paused state. */ heap->dbg_processing = 0; @@ -16888,7 +17208,7 @@ DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) { DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); - /* Can be called muliple times with no harm. */ + /* Can be called multiple times with no harm. */ duk_debug_do_detach(thr->heap); } @@ -16936,12 +17256,12 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx, DUK_UNREF(write_flush_cb); DUK_UNREF(detached_cb); DUK_UNREF(udata); - duk_error(ctx, DUK_ERR_API_ERROR, "no debugger support"); + DUK_ERROR_API((duk_hthread *) ctx, "no debugger support"); } DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) { DUK_ASSERT_CTX_VALID(ctx); - duk_error(ctx, DUK_ERR_API_ERROR, "no debugger support"); + DUK_ERROR_API((duk_hthread *) ctx, "no debugger support"); } DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) { @@ -17860,23 +18180,25 @@ DUK_EXTERNAL duk_int_t duk_api_global_line = 0; #endif /* - * Helpers + * Misc helpers */ /* Check that there's room to push one value. */ #if defined(DUK_USE_VALSTACK_UNSAFE) /* Faster but value stack overruns are memory unsafe. */ -#define DUK__CHECK_SPACE() do { \ +#define DUK__CHECK_SPACE() do { \ DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \ } while (0) #else -#define DUK__CHECK_SPACE() do { \ - if (thr->valstack_top >= thr->valstack_end) { \ - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \ +#define DUK__CHECK_SPACE() do { \ + if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \ + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \ } \ } while (0) #endif +DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag); + DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) { duk_hthread *thr; duk_tval *tv; @@ -17938,7 +18260,7 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_b error_notnumber: if (require) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NUMBER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } return 0; @@ -17995,7 +18317,7 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk error_notnumber: if (require) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NUMBER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); /* not reachable */ } return 0; @@ -18071,7 +18393,7 @@ DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t i if (DUK_LIKELY(uindex < vs_size)) { return (duk_idx_t) uindex; } - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX); + DUK_ERROR_API_INDEX(thr, index); return 0; /* unreachable */ } @@ -18129,7 +18451,7 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) { if (DUK_LIKELY(uindex < vs_size)) { return thr->valstack_bottom + uindex; } - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX); + DUK_ERROR_API_INDEX(thr, index); return NULL; } @@ -18149,7 +18471,8 @@ DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) { DUK_ASSERT(DUK_INVALID_INDEX < 0); if (duk_normalize_index(ctx, index) < 0) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX); + DUK_ERROR_API_INDEX(thr, index); + return; /* unreachable */ } } @@ -18202,10 +18525,11 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) { #if defined(DUK_USE_VALSTACK_UNSAFE) DUK_ASSERT(uindex <= vs_limit); + DUK_UNREF(vs_limit); #else if (DUK_UNLIKELY(uindex > vs_limit)) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX); - return; + DUK_ERROR_API_INDEX(thr, index); + return; /* unreachable */ } #endif DUK_ASSERT(uindex <= vs_limit); @@ -18284,7 +18608,8 @@ DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) { ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1; if (DUK_UNLIKELY(ret < 0)) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX); + DUK_ERROR_API_INDEX(thr, -1); + return 0; /* unreachable */ } return ret; } @@ -18680,7 +19005,8 @@ DUK_EXTERNAL void duk_dup_top(duk_context *ctx) { DUK__CHECK_SPACE(); if (thr->valstack_top - thr->valstack_bottom <= 0) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_INDEX); + DUK_ERROR_API_INDEX(thr, -1); + return; /* unreachable */ } tv_from = thr->valstack_top - 1; tv_to = thr->valstack_top++; @@ -18721,7 +19047,7 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) { if (nbytes > 0) { DUK_TVAL_SET_TVAL(&tv_tmp, q); DUK_ASSERT(nbytes > 0); - DUK_MEMMOVE((void *) (p + 1), (void *) p, nbytes); + DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes); DUK_TVAL_SET_TVAL(p, &tv_tmp); } else { /* nop: insert top to top */ @@ -18800,7 +19126,7 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) { #endif nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ - DUK_MEMMOVE(p, p + 1, nbytes); /* zero size not an issue: pointers are valid */ + DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */ DUK_TVAL_SET_UNDEFINED(q); thr->valstack_top--; @@ -18830,13 +19156,13 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, DUK_ASSERT(from_ctx != NULL); if (to_ctx == from_ctx) { - DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CONTEXT); + DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT); return; } if ((count < 0) || (count > (duk_idx_t) to_thr->valstack_max)) { /* Maximum value check ensures 'nbytes' won't wrap below. */ - DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT); + DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT); return; } @@ -18846,18 +19172,18 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, } DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) { - DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); if (src < (void *) from_thr->valstack_bottom) { - DUK_ERROR(to_thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT); + DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT); } /* copy values (no overlap even if to_ctx == from_ctx; that's not * allowed now anyway) */ DUK_ASSERT(nbytes > 0); - DUK_MEMCPY((void *) to_thr->valstack_top, src, nbytes); + DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes); p = to_thr->valstack_top; to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes); @@ -18895,10 +19221,10 @@ DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) { tv = duk_get_tval(ctx, index); if (tv && DUK_TVAL_IS_UNDEFINED(tv)) { - /* Note: accept both 'actual' and 'unused' undefined */ return; } - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_UNDEFINED); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED); + return; /* not reachable */ } DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) { @@ -18911,7 +19237,7 @@ DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) { if (tv && DUK_TVAL_IS_NULL(tv)) { return; } - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NULL); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL); return; /* not reachable */ } @@ -18942,8 +19268,7 @@ DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) { DUK_ASSERT(ret == 0 || ret == 1); return ret; } - - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_BOOLEAN); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN); return 0; /* not reachable */ } @@ -18987,8 +19312,7 @@ DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret); return ret.d; } - - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NUMBER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER); return DUK_DOUBLE_NAN; /* not reachable */ } @@ -19057,8 +19381,7 @@ DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, if (ret) { return ret; } - - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_STRING); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING); return NULL; /* not reachable */ } @@ -19102,8 +19425,7 @@ DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) { void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ return (void *) p; } - - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_POINTER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER); return NULL; /* not reachable */ } @@ -19146,7 +19468,7 @@ DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_si } if (throw_flag) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_BUFFER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER); } return NULL; } @@ -19208,7 +19530,7 @@ DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, d fail: if (throw_flag) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_BUFFER); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER); } return NULL; } @@ -19221,78 +19543,68 @@ DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, du return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/); } -/* Raw helper for getting a value from the stack, checking its tag, and possible its object class. - * The tag cannot be a number because numbers don't have an internal tag in the packed representation. +/* Raw helper for getting a value from the stack, checking its tag. + * The tag cannot be a number because numbers don't have an internal + * tag in the packed representation. */ -DUK_INTERNAL duk_heaphdr *duk_get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t flags_and_tag) { - duk_hthread *thr = (duk_hthread *) ctx; + +DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) { duk_tval *tv; - duk_small_uint_t tag = flags_and_tag & 0xffffU; /* tags can be up to 16 bits */ DUK_ASSERT_CTX_VALID(ctx); tv = duk_get_tval(ctx, index); if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) { duk_heaphdr *ret; - - /* Note: tag comparison in general doesn't work for numbers, - * but it does work for everything else (heap objects here). - */ ret = DUK_TVAL_GET_HEAPHDR(tv); DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */ - - /* If class check has been requested, tag must also be DUK_TAG_OBJECT. - * This allows us to just check the class check flag without checking - * the tag also. - */ - DUK_ASSERT((flags_and_tag & DUK_GETTAGGED_FLAG_CHECK_CLASS) == 0 || - tag == DUK_TAG_OBJECT); - - if ((flags_and_tag & DUK_GETTAGGED_FLAG_CHECK_CLASS) == 0 || /* no class check */ - (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) ret) == /* or class check matches */ - (duk_int_t) ((flags_and_tag >> DUK_GETTAGGED_CLASS_SHIFT) & 0xff)) { - return ret; - } - } - - if (flags_and_tag & DUK_GETTAGGED_FLAG_ALLOW_NULL) { - return (duk_heaphdr *) NULL; + return ret; } - /* Formatting the tag number here is not very useful: the tag value - * is Duktape internal (not the same as DUK_TYPE_xxx) and even depends - * on the duk_tval layout. If anything, add a human readable type here. - */ - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE); - return NULL; /* not reachable */ + return (duk_heaphdr *) NULL; } DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) { - return (duk_hstring *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING | DUK_GETTAGGED_FLAG_ALLOW_NULL); + return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING); } DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) { - return (duk_hstring *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING); + duk_heaphdr *h; + h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING); + if (h == NULL) { + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING); + } + return (duk_hstring *) h; } DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) { - return (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL); + return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); } DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) { - return (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + duk_heaphdr *h; + h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (h == NULL) { + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT); + } + return (duk_hobject *) h; } DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) { - return (duk_hbuffer *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER | DUK_GETTAGGED_FLAG_ALLOW_NULL); + return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER); } DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) { - return (duk_hbuffer *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER); + duk_heaphdr *h; + h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER); + if (h == NULL) { + DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER); + } + return (duk_hbuffer *) h; } DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) { - duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) { h = NULL; } @@ -19301,16 +19613,15 @@ DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) { DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); - DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_THREAD(h)) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_THREAD); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD); } return (duk_hthread *) h; } DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) { - duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { h = NULL; } @@ -19319,16 +19630,15 @@ DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); - DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_COMPILEDFUNCTION); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION); } return (duk_hcompiledfunction *) h; } DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) { - duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { h = NULL; } @@ -19337,10 +19647,9 @@ DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_ DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) { duk_hthread *thr = (duk_hthread *) ctx; - duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); - DUK_ASSERT(h != NULL); - if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_NATIVEFUNCTION); + duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) { + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION); } return (duk_hnativefunction *) h; } @@ -19379,11 +19688,17 @@ DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t i ret = duk_get_c_function(ctx, index); if (!ret) { - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_C_FUNCTION); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION); } return ret; } +DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) { + if (!duk_is_function(ctx, index)) { + DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION); + } +} + DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) { DUK_ASSERT_CTX_VALID(ctx); @@ -19427,7 +19742,7 @@ DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) { return ret; } - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE); return (void *) NULL; /* not reachable */ } @@ -19444,7 +19759,7 @@ duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) { * to an object). Return value is NULL if value is neither an object nor a * lightfunc. */ -duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) { +DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) { duk_tval *tv; DUK_ASSERT_CTX_VALID(ctx); @@ -19477,8 +19792,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { return NULL; } - - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT); return NULL; /* not reachable */ } @@ -19499,11 +19813,44 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_to_object(ctx, index); return duk_require_hobject(ctx, index); } - - DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE); + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT); return NULL; /* not reachable */ } +DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) { + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ + DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); + + h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) { + h = NULL; + } + return h; +} + +DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) { + duk_hthread *thr; + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ + DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); + thr = (duk_hthread *) ctx; + + h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT); + if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) { + duk_hstring *h_class; + h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); + DUK_UNREF(h_class); + + DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE); + } + return h; +} + DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) { duk_tval *tv; @@ -19914,6 +20261,50 @@ DUK_EXTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) } #endif +/* Coerce top into Object.prototype.toString() output. */ +DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) { + duk_hthread *thr; + duk_uint_t typemask; + duk_hstring *h_strclass; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + + typemask = duk_get_type_mask(ctx, -1); + if (typemask & DUK_TYPE_MASK_UNDEFINED) { + h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr); + } else if (typemask & DUK_TYPE_MASK_NULL) { + h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr); + } else { + duk_hobject *h_obj; + + duk_to_object(ctx, -1); + h_obj = duk_get_hobject(ctx, -1); + DUK_ASSERT(h_obj != NULL); + + h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj); + } + DUK_ASSERT(h_strclass != NULL); + + duk_pop(ctx); + duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass)); +} + +#if !defined(DUK_USE_PARANOID_ERRORS) +DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) { + duk_hthread *thr; + duk_hstring *h_strclass; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(h != NULL); + thr = (duk_hthread *) ctx; + + h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h); + DUK_ASSERT(h_strclass != NULL); + duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass)); +} +#endif /* !DUK_USE_PARANOID_ERRORS */ + /* XXX: other variants like uint, u32 etc */ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) { duk_hthread *thr = (duk_hthread *) ctx; @@ -20102,8 +20493,10 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size * duk_to_dynamic_buffer() call. */ duk_uint_t tmp; + duk_uint8_t *tmp_ptr; - src_data = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf); + tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf); + src_data = (const duk_uint8_t *) tmp_ptr; src_size = DUK_HBUFFER_GET_SIZE(h_buf); tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED); @@ -20112,7 +20505,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size /* Note: src_data may be NULL if input is a zero-size * dynamic buffer. */ - dst_data = (duk_uint8_t *) src_data; + dst_data = tmp_ptr; goto skip_copy; } } else { @@ -20131,7 +20524,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size * target buffer is dynamic). Avoid zero-size memcpy() * with an invalid pointer. */ - DUK_MEMCPY(dst_data, src_data, src_size); + DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size); } duk_replace(ctx, index); skip_copy: @@ -20410,6 +20803,31 @@ DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) { DUK_UNREACHABLE(); } +#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) +DUK_LOCAL const char *duk__type_names[] = { + "none", + "undefined", + "null", + "boolean", + "number", + "string", + "object", + "buffer", + "pointer", + "lightfunc" +}; + +DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) { + duk_int_t type_tag; + + type_tag = duk_get_type(ctx, index); + DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX); + DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1); + + return duk__type_names[type_tag]; +} +#endif + DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) { DUK_ASSERT_CTX_VALID(ctx); @@ -20616,12 +21034,6 @@ DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) { DUK_HOBJECT_FLAG_THREAD); } -DUK_EXTERNAL duk_bool_t duk_is_callable(duk_context *ctx, duk_idx_t index) { - /* XXX: currently same as duk_is_function() */ - DUK_ASSERT_CTX_VALID(ctx); - return duk_is_function(ctx, index); -} - DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) { duk_tval *tv; @@ -20888,7 +21300,7 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk /* check stack before interning (avoid hanging temp) */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } /* NULL with zero length represents an empty string; NULL with higher @@ -20905,7 +21317,7 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, DUK_STR_STRING_TOO_LONG); } - h = duk_heap_string_intern_checked(thr, (duk_uint8_t *) str, (duk_uint32_t) len); + h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); DUK_ASSERT(h != NULL); tv_slot = thr->valstack_top++; @@ -21164,7 +21576,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ct duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); if (!target_ctx) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); return; /* not reached */ } duk_push_hobject(ctx, (duk_hobject *) target_ctx); @@ -21241,7 +21653,7 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va /* failed, resize and try again */ sz = sz * 2; if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_SPRINTF_TOO_LONG); + DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG); } } @@ -21281,7 +21693,7 @@ DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobje /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } h = duk_hobject_alloc(thr->heap, hobject_flags_and_class); @@ -21381,7 +21793,7 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) { /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } obj = duk_hthread_alloc(thr->heap, @@ -21440,7 +21852,7 @@ DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) { /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } /* Template functions are not strictly constructable (they don't @@ -21481,7 +21893,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } if (func == NULL) { goto api_error; @@ -21517,7 +21929,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu return ret; api_error: - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); return 0; /* not reached */ } @@ -21578,7 +21990,7 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { @@ -21602,7 +22014,7 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1; api_error: - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); return 0; /* not reached */ } @@ -21616,7 +22028,7 @@ DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_ /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class); @@ -21859,7 +22271,7 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_sm /* check stack first */ if (thr->valstack_top >= thr->valstack_end) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); + DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); } /* Check for maximum buffer length. */ @@ -21892,7 +22304,7 @@ DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) { goto push_undefined; } - switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { + switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { case DUK_HTYPE_STRING: duk_push_hstring(ctx, (duk_hstring *) ptr); break; @@ -21969,13 +22381,13 @@ DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) { DUK_ASSERT_CTX_VALID(ctx); if (DUK_UNLIKELY(count < 0)) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT); + DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT); return; } DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_POP_TOO_MANY); + DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY); } /* @@ -22027,7 +22439,7 @@ DUK_EXTERNAL void duk_pop(duk_context *ctx) { DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_POP_TOO_MANY); + DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY); } tv = --thr->valstack_top; /* tv points to element just below prev top */ @@ -22063,7 +22475,7 @@ DUK_EXTERNAL void duk_throw(duk_context *ctx) { DUK_ASSERT(thr->valstack_end >= thr->valstack_top); if (thr->valstack_top == thr->valstack_bottom) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); } /* Errors are augmented when they are created, not when they are @@ -22283,7 +22695,129 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du duk_push_lstring(ctx, (const char *) buf, sz * 2); } +#if !defined(DUK_USE_PARANOID_ERRORS) +/* + * Push readable string summarizing duk_tval. The operation is side effect + * free and will only throw from internal errors (e.g. out of memory). + * This is used by e.g. property access code to summarize a key/base safely, + * and is not intended to be fast (but small and safe). + */ + +#define DUK__READABLE_STRING_MAXCHARS 32 + +/* String sanitizer which escapes ASCII control characters and a few other + * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with + * question marks. No errors are thrown for any input string, except in out + * of memory situations. + */ +DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) { + duk_hthread *thr; + const duk_uint8_t *p, *p_start, *p_end; + duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS + + 2 /*quotes*/ + 3 /*periods*/]; + duk_uint8_t *q; + duk_ucodepoint_t cp; + duk_small_uint_t nchars; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(h_input != NULL); + thr = (duk_hthread *) ctx; + + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); + p = p_start; + q = buf; + + nchars = 0; + *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; + for (;;) { + if (p >= p_end) { + break; + } + if (nchars == DUK__READABLE_STRING_MAXCHARS) { + *q++ = (duk_uint8_t) DUK_ASC_PERIOD; + *q++ = (duk_uint8_t) DUK_ASC_PERIOD; + *q++ = (duk_uint8_t) DUK_ASC_PERIOD; + break; + } + if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) { + if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) { + DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */ + DUK_ASSERT((cp >> 4) <= 0x0f); + *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH; + *q++ = (duk_uint8_t) DUK_ASC_LC_X; + *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4]; + *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f]; + } else { + q += duk_unicode_encode_xutf8(cp, q); + } + } else { + p++; /* advance manually */ + *q++ = (duk_uint8_t) DUK_ASC_QUESTION; + } + nchars++; + } + *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; + + duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf)); +} + +DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) { + duk_hthread *thr; + + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + + if (tv == NULL) { + duk_push_string(ctx, "none"); + } else { + switch (DUK_TVAL_GET_TAG(tv)) { + case DUK_TAG_STRING: { + duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv)); + break; + } + case DUK_TAG_OBJECT: { + duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + duk_push_hobject_class_string(ctx, h); + break; + } + case DUK_TAG_BUFFER: { + /* XXX: Hex encoded, length limited buffer summary here? */ + duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h != NULL); + duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h)); + break; + } + case DUK_TAG_POINTER: { + /* Surround with parentheses like in JX, ensures NULL pointer + * is distinguishable from null value ("(null)" vs "null"). + */ + duk_push_tval(ctx, tv); + duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1)); + duk_remove(ctx, -2); + break; + } + default: { + duk_push_tval(ctx, tv); + break; + } + } + } + + return duk_to_string(ctx, -1); +} + +DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) { + DUK_ASSERT_CTX_VALID(ctx); + return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index)); +} +#endif /* !DUK_USE_PARANOID_ERRORS */ + #undef DUK__CHECK_SPACE +#undef DUK__PACK_ARGS +#undef DUK__READABLE_STRING_MAXCHARS #line 1 "duk_api_string.c" /* * String manipulation @@ -22304,7 +22838,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, if (DUK_UNLIKELY(count_in <= 0)) { if (count_in < 0) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_COUNT); + DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT); return; } DUK_ASSERT(count_in == 0); @@ -22420,7 +22954,7 @@ DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decod h_input = duk_require_hstring(ctx, index); DUK_ASSERT(h_input != NULL); - p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); p = p_start; @@ -22451,7 +22985,7 @@ DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char bw = &bw_alloc; DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */ - p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); p = p_start; @@ -22585,7 +23119,8 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) { DUK_ASSERT(q_end >= q_start); DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p", - (void *) p_start, (void *) p_end, (void *) q_start, (void *) q_end)); + (const void *) p_start, (const void *) p_end, + (const void *) q_start, (const void *) q_end)); if (q_start == p_start && q_end == p_end) { DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)")); @@ -23932,9 +24467,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) { DUK_ASSERT_TOP(ctx, 2); len = duk__push_this_obj_len_u32(ctx); - if (!duk_is_callable(ctx, 0)) { - goto type_error; - } + duk_require_callable(ctx, 0); /* if thisArg not supplied, behave as if undefined was supplied */ if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) { @@ -24049,9 +24582,6 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) { } return 1; - - type_error: - return DUK_RET_TYPE_ERROR; } /* @@ -24619,7 +25149,7 @@ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx, DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { duk_double_union du; - DUK_MEMCPY((void *) du.uc, (const void *) p, elem_size); + DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size); switch (h_bufobj->elem_type) { case DUK_HBUFFEROBJECT_ELEM_UINT8: @@ -24703,7 +25233,7 @@ DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbuffe DUK_UNREACHABLE(); } - DUK_MEMCPY((void *) p, (const void *) du.uc, elem_size); + DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size); } /* @@ -24894,9 +25424,14 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) { #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) { + duk_hthread *thr; duk_hbufferobject *h_bufobj; duk_hbuffer *h_val; + DUK_ASSERT_CTX_VALID(ctx); + thr = (duk_hthread *) ctx; + DUK_UNREF(thr); + /* XXX: function flag to make this automatic? */ if (!duk_is_constructor_call(ctx)) { return DUK_RET_TYPE_ERROR; @@ -24920,6 +25455,14 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) { (void) duk_push_fixed_buffer(ctx, (duk_size_t) len); h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1); DUK_ASSERT(h_val != NULL); + +#if !defined(DUK_USE_ZERO_BUFFER_DATA) + /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA + * is not set. + */ + DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val)); + DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len); +#endif } h_bufobj = duk_push_bufferobject_raw(ctx, @@ -25131,6 +25674,14 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { elem_length_signed = (duk_int_t) duk_get_length(ctx, 0); copy_mode = 2; } + } else if (DUK_TVAL_IS_BUFFER(tv)) { + /* Accept plain buffer values like array initializers + * (new in Duktape 1.4.0). + */ + duk_hbuffer *h_srcbuf; + h_srcbuf = DUK_TVAL_GET_BUFFER(tv); + elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf); + copy_mode = 2; /* XXX: could add fast path for u8 compatible views */ } else { /* Non-object argument is simply int coerced, matches * V8 behavior (except for "null", which we coerce to @@ -25277,6 +25828,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) { * ambiguity with Float32/Float64 because zero bytes also * represent 0.0. */ +#if !defined(DUK_USE_ZERO_BUFFER_DATA) + /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA + * is not set. + */ + DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val)); + DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length); +#endif DUK_DDD(DUK_DDDPRINT("using no copy")); break; @@ -25419,7 +25977,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) { if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) { DUK_MEMCPY((void *) buf_slice, (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset), - slice_length); + (size_t) slice_length); } else { /* not covered, return all zeroes */ ; @@ -28835,7 +29393,10 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) { #if defined(DUK_USE_DATE_NOW_TIME) /* Not a very good provider: only full seconds are available. */ DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) { - time_t t = time(NULL); + time_t t; + + DUK_UNREF(ctx); + t = time(NULL); return ((duk_double_t) t) * 1000.0; } #endif /* DUK_USE_DATE_NOW_TIME */ @@ -28951,6 +29512,13 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year, (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst)); + /* tm_isdst is both an input and an output to mktime(), use 0 to + * avoid DST handling in mktime(): + * - https://github.com/svaarala/duktape/issues/406 + * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst + */ + tms[0].tm_isdst = 0; + tms[1].tm_isdst = 0; t1 = mktime(&tms[0]); /* UTC */ t2 = mktime(&tms[1]); /* local */ if (t1 == (time_t) -1 || t2 == (time_t) -1) { @@ -28961,11 +29529,6 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { */ goto error; } - if (tms[1].tm_isdst > 0) { - t2 += 3600; - } else if (tms[1].tm_isdst < 0) { - DUK_D(DUK_DPRINT("tm_isdst is negative: %d", (int) tms[1].tm_isdst)); - } DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2)); /* Compute final offset in seconds, positive if local time ahead of @@ -29612,7 +30175,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) { return 1; } -#ifdef DUK_USE_TRACEBACKS +#if defined(DUK_USE_TRACEBACKS) /* * Traceback handling @@ -29633,11 +30196,12 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) { #define DUK__OUTPUT_TYPE_FILENAME 0 #define DUK__OUTPUT_TYPE_LINENUMBER 1 -DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int_t output_type) { +DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t idx_td; duk_small_int_t i; /* traceback depth fits into 16 bits */ duk_small_int_t t; /* stack type fits into 16 bits */ + duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */ const char *str_tailcalled = " tailcalled"; const char *str_strict = " strict"; const char *str_construct = " construct"; @@ -29683,6 +30247,8 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int * Ecmascript/native function call or lightfunc call */ + count_func++; + /* [ ... v1(func) v2(pc+flags) ] */ h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */ @@ -29698,11 +30264,16 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int /* [ ... v1 v2 name filename ] */ - if (output_type == DUK__OUTPUT_TYPE_FILENAME) { - return 1; - } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { - duk_push_int(ctx, line); - return 1; + /* When looking for .fileName/.lineNumber, blame first + * function which has a .fileName. + */ + if (duk_is_string(ctx, -1)) { + if (output_type == DUK__OUTPUT_TYPE_FILENAME) { + return 1; + } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { + duk_push_int(ctx, line); + return 1; + } } h_name = duk_get_hstring(ctx, -2); /* may be NULL */ @@ -29752,6 +30323,9 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int /* [ ... v1(filename) v2(line+flags) ] */ + /* When looking for .fileName/.lineNumber, blame compilation + * or C call site unless flagged not to do so. + */ if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { duk_pop(ctx); @@ -29773,7 +30347,7 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int } } - if (i >= DUK_USE_TRACEBACK_DEPTH * 2) { + if (count_func >= DUK_USE_TRACEBACK_DEPTH) { /* Possibly truncated; there is no explicit truncation * marker so this is the best we can do. */ @@ -29796,20 +30370,20 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int } } -/* XXX: output type could be encoded into native function 'magic' value to - * save space. +/* XXX: Output type could be encoded into native function 'magic' value to + * save space. For setters the stridx could be encoded into 'magic'. */ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) { - return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK); + return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK); } DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) { - return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME); + return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME); } DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) { - return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER); + return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER); } #undef DUK__OUTPUT_TYPE_TRACEBACK @@ -29849,14 +30423,43 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx #endif /* DUK_USE_TRACEBACKS */ -DUK_INTERNAL duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx) { - /* Attempt to write 'stack', 'fileName', 'lineNumber' is a silent no-op. - * User can use Object.defineProperty() to override this behavior. +DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) { + /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if + * user code called Object.defineProperty() to create an overriding + * own property. This allows user code to overwrite .fileName etc + * intuitively as e.g. "err.fileName = 'dummy'" as one might expect. + * See https://github.com/svaarala/duktape/issues/387. */ - DUK_ASSERT_TOP(ctx, 1); /* fixed arg count */ - DUK_UNREF(ctx); + + DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */ + + duk_push_this(ctx); + duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key); + duk_dup(ctx, 0); + + /* [ ... obj key value ] */ + + DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T", + duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1))); + + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | + DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE | + DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/ + DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE); return 0; } + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) { + return duk__error_setter_helper(ctx, DUK_STRIDX_STACK); +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) { + return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME); +} + +DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) { + return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER); +} #line 1 "duk_bi_function.c" /* * Function built-ins @@ -30300,7 +30903,7 @@ typedef struct { const duk_uint8_t *p_end; } duk__transform_context; -typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp); +typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp); /* XXX: refactor and share with other code */ DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) { @@ -30320,7 +30923,7 @@ DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small return t; } -DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, void *udata) { +DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) { duk_hthread *thr = (duk_hthread *) ctx; duk__transform_context tfm_ctx_alloc; duk__transform_context *tfm_ctx = &tfm_ctx_alloc; @@ -30348,12 +30951,12 @@ DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback ca return 1; } -DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) { +DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH]; duk_small_int_t len; duk_codepoint_t cp1, cp2; duk_small_int_t i, t; - const duk_uint8_t *unescaped_table = (duk_uint8_t *) udata; + const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata; /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes. * Codepoint range is restricted so this is a slightly too large @@ -30410,8 +31013,8 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input"); } -DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) { - const duk_uint8_t *reserved_table = (duk_uint8_t *) udata; +DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { + const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata; duk_small_uint_t utf8_blen; duk_codepoint_t min_cp; duk_small_int_t t; /* must be signed */ @@ -30549,7 +31152,7 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct } #ifdef DUK_USE_SECTION_B -DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) { +DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { DUK_UNREF(udata); DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6); @@ -30588,7 +31191,7 @@ DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, v DUK_ERROR(tfm_ctx->thr, DUK_ERR_TYPE_ERROR, "invalid input"); } -DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) { +DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { duk_small_int_t t; DUK_UNREF(udata); @@ -30634,6 +31237,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { duk_hobject *outer_var_env; duk_bool_t this_to_global = 1; duk_small_uint_t comp_flags; + duk_int_t level = -2; DUK_ASSERT_TOP(ctx, 1); DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ @@ -30653,15 +31257,26 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { return 1; /* return arg as-is */ } +#if defined(DUK_USE_DEBUGGER_SUPPORT) + /* NOTE: level is used only by the debugger and should never be present + * for an Ecmascript eval(). + */ + DUK_ASSERT(level == -2); /* by default, use caller's environment */ + if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) { + level = duk_get_int(ctx, 1); + } + DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */ +#endif + /* [ source ] */ comp_flags = DUK_JS_COMPILE_FLAG_EVAL; act_eval = thr->callstack + thr->callstack_top - 1; /* this function */ - if (thr->callstack_top >= 2) { + if (thr->callstack_top >= (duk_size_t) -level) { /* Have a calling activation, check for direct eval (otherwise * assume indirect eval. */ - act_caller = thr->callstack + thr->callstack_top - 2; /* caller */ + act_caller = thr->callstack + thr->callstack_top + level; /* caller */ if ((act_caller->flags & DUK_ACT_FLAG_STRICT) && (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) { /* Only direct eval inherits strictness from calling code @@ -30691,14 +31306,14 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { act = thr->callstack + thr->callstack_top - 1; /* this function */ if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { DUK_ASSERT(thr->callstack_top >= 2); - act = thr->callstack + thr->callstack_top - 2; /* caller */ + act = thr->callstack + thr->callstack_top + level; /* caller */ if (act->lex_env == NULL) { DUK_ASSERT(act->var_env == NULL); DUK_DDD(DUK_DDDPRINT("delayed environment initialization")); /* this may have side effects, so re-lookup act */ duk_js_init_activation_environment_records_delayed(thr, act); - act = thr->callstack + thr->callstack_top - 2; + act = thr->callstack + thr->callstack_top + level; } DUK_ASSERT(act->lex_env != NULL); DUK_ASSERT(act->var_env != NULL); @@ -30713,7 +31328,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { "var_env and lex_env to a fresh env, " "this_binding to caller's this_binding")); - act = thr->callstack + thr->callstack_top - 2; /* caller */ + act = thr->callstack + thr->callstack_top + level; /* caller */ act_lex_env = act->lex_env; act = NULL; /* invalidated */ @@ -30764,7 +31379,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { } else { duk_tval *tv; DUK_ASSERT(thr->callstack_top >= 2); - act = thr->callstack + thr->callstack_top - 2; /* caller */ + act = thr->callstack + thr->callstack_top + level; /* caller */ tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */ DUK_ASSERT(tv >= thr->valstack); duk_push_tval(ctx, tv); @@ -30789,44 +31404,39 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) { */ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) { - duk_bool_t strip_prefix; duk_int32_t radix; duk_small_uint_t s2n_flags; DUK_ASSERT_TOP(ctx, 2); duk_to_string(ctx, 0); - strip_prefix = 1; radix = duk_to_int32(ctx, 1); + + s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | + DUK_S2N_FLAG_ALLOW_GARBAGE | + DUK_S2N_FLAG_ALLOW_PLUS | + DUK_S2N_FLAG_ALLOW_MINUS | + DUK_S2N_FLAG_ALLOW_LEADING_ZERO | + DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; + + /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT. + * + * Don't autodetect octals (from leading zeroes), require user code to + * provide an explicit radix 8 for parsing octal. See write-up from Mozilla: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation + */ + if (radix != 0) { if (radix < 2 || radix > 36) { goto ret_nan; } - /* For octal, setting strip_prefix=0 is not necessary, as zero - * is tolerated anyway: - * - * parseInt('123', 8) === parseInt('0123', 8) with or without strip_prefix - * parseInt('123', 16) === parseInt('0x123', 16) requires strip_prefix = 1 - */ if (radix != 16) { - strip_prefix = 0; + s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; } } else { radix = 10; } - s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | - DUK_S2N_FLAG_ALLOW_GARBAGE | - DUK_S2N_FLAG_ALLOW_PLUS | - DUK_S2N_FLAG_ALLOW_MINUS | - DUK_S2N_FLAG_ALLOW_LEADING_ZERO | -#ifdef DUK_USE_OCTAL_SUPPORT - (strip_prefix ? (DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT | DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) : 0) -#else - (strip_prefix ? DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT : 0) -#endif - ; - duk_dup(ctx, 0); duk_numconv_parse(ctx, radix, s2n_flags); return 1; @@ -30882,28 +31492,28 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) { */ DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) { - return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (void *) duk__decode_uri_reserved_table); + return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table); } DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) { - return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (void *) duk__decode_uri_component_reserved_table); + return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table); } DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) { - return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (void *) duk__encode_uriunescaped_table); + return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table); } DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) { - return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (void *) duk__encode_uricomponent_unescaped_table); + return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table); } #ifdef DUK_USE_SECTION_B DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) { - return duk__transform_helper(ctx, duk__transform_callback_escape, (void *) NULL); + return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL); } DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) { - return duk__transform_helper(ctx, duk__transform_callback_unescape, (void *) NULL); + return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL); } #else /* DUK_USE_SECTION_B */ DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) { @@ -30974,13 +31584,13 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) { } if (sz_buf <= sizeof(buf_stack)) { - buf = (const duk_uint8_t *) buf_stack; + p = (duk_uint8_t *) buf_stack; } else { - buf = (const duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf); - DUK_ASSERT(buf != NULL); + p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf); + DUK_ASSERT(p != NULL); } - p = (duk_uint8_t *) buf; + buf = (const duk_uint8_t *) p; for (i = 0; i < nargs; i++) { p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str); DUK_ASSERT(p_str != NULL); @@ -31474,9 +32084,10 @@ DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p); DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx); DUK_LOCAL_DECL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q); DUK_LOCAL_DECL duk_bool_t duk__enc_key_quotes_needed(duk_hstring *h_key); +DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k); DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str); -DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top); -DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top); +DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); +DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx); DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx); DUK_LOCAL_DECL duk_bool_t duk__enc_value1(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder); @@ -31486,6 +32097,14 @@ DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx); #if defined(DUK_USE_FASTINT) DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); #endif +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); +DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj); +#endif +#endif +DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth); /* * Helper tables @@ -31700,7 +32319,7 @@ DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) { duk_hstring *h; - duk_uint8_t *p; + const duk_uint8_t *p; duk_uint8_t x, y; /* First character has already been eaten and checked by the caller. @@ -31713,7 +32332,7 @@ DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t st h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); DUK_ASSERT(h != NULL); - p = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1; + p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1; DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */ for (;;) { @@ -31996,12 +32615,26 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) { duk_hthread *thr = js_ctx->thr; duk_context *ctx = (duk_context *) thr; const duk_uint8_t *p; + duk_uint8_t *buf; + duk_size_t src_len; duk_small_int_t x; /* Caller has already eaten the first character ('|') which we don't need. */ p = js_ctx->p; + /* XXX: Would be nice to share the fast path loop from duk_hex_decode() + * and avoid creating a temporary buffer. However, there are some + * differences which prevent trivial sharing: + * + * - Pipe char detection + * - EOF detection + * - Unknown length of input and output + * + * The best approach here would be a bufwriter and a reasonaly sized + * safe inner loop (e.g. 64 output bytes at a time). + */ + for (;;) { x = *p; @@ -32017,8 +32650,12 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) { p++; } - duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p)); + src_len = (duk_size_t) (p - js_ctx->p); + buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len); + DUK_ASSERT(buf != NULL); + DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len); duk_hex_decode(ctx, -1); + js_ctx->p = p + 1; /* skip '|' */ /* [ ... buf ] */ @@ -32052,8 +32689,8 @@ DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) { x = *p; DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld", - (void *) p_start, (void *) p, - (void *) js_ctx->p_end, (long) x)); + (const void *) p_start, (const void *) p, + (const void *) js_ctx->p_end, (long) x)); #if defined(DUK_USE_JSON_DECNUMBER_FASTPATH) /* This fast path is pretty marginal in practice. @@ -32552,7 +33189,8 @@ DUK_LOCAL duk_bool_t duk__enc_key_quotes_needed(duk_hstring *h_key) { p = p_start; DUK_DDD(DUK_DDDPRINT("duk__enc_key_quotes_needed: h_key=%!O, p_start=%p, p_end=%p, p=%p", - (duk_heaphdr *) h_key, (void *) p_start, (void *) p_end, (void *) p)); + (duk_heaphdr *) h_key, (const void *) p_start, + (const void *) p_end, (const void *) p)); /* Since we only accept ASCII characters, there is no need for * actual decoding. A non-ASCII character will be >= 0x80 which @@ -32583,6 +33221,17 @@ DUK_LOCAL duk_bool_t duk__enc_key_quotes_needed(duk_hstring *h_key) { return 0; } +DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) { + /* XXX: could reimplement so that we start emitting the key without + * quotes and backtrack if we hit a problem character. + */ + if (js_ctx->flag_avoid_key_quotes && !duk__enc_key_quotes_needed(k)) { + DUK__EMIT_HSTR(js_ctx, k); + } else { + duk__enc_quote_string(js_ctx, k); + } +} + /* The Quote(value) operation: quote a string. * * Stack policy: [ ] -> [ ]. @@ -32757,7 +33406,7 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) { * it would otherwise serialize to '0', not '-0'. */ if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 && - (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible))) { + (js_ctx->flag_ext_custom_or_compatible))) { duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */ } else #endif /* DUK_USE_JX || DUK_USE_JC */ @@ -32814,35 +33463,306 @@ DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) { } #endif -/* Shared entry handling for object/array serialization: indent/stepback, - * loop detection. +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +#if defined(DUK_USE_HEX_FASTPATH) +DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { + duk_uint8_t *q; + duk_uint16_t *q16; + duk_small_uint_t x; + duk_size_t i, len_safe; +#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) + duk_bool_t shift_dst; +#endif + + /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2. + * For platforms where unaligned accesses are not allowed, shift 'dst' + * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result + * in place. The faster encoding loop makes up the difference. + * There's always space for one extra byte because a terminator always + * follows the hex data and that's been accounted for by the caller. + */ + +#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) + q16 = (duk_uint16_t *) (void *) dst; +#else + shift_dst = (duk_bool_t) (((duk_uintptr_t) dst) & 0x01U); + if (shift_dst) { + DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1")); + q16 = (duk_uint16_t *) (void *) (dst + 1); + } else { + DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned")); + q16 = (duk_uint16_t *) (void *) dst; + } + DUK_ASSERT((((duk_uintptr_t) q16) & 0x01U) == 0); +#endif + + len_safe = src_len & ~0x03U; + for (i = 0; i < len_safe; i += 4) { + q16[0] = duk_hex_enctab[src[i]]; + q16[1] = duk_hex_enctab[src[i + 1]]; + q16[2] = duk_hex_enctab[src[i + 2]]; + q16[3] = duk_hex_enctab[src[i + 3]]; + q16 += 4; + } + q = (duk_uint8_t *) q16; + +#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) + if (shift_dst) { + q--; + DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe); + DUK_ASSERT(dst + 2 * len_safe == q); + } +#endif + + for (; i < src_len; i++) { + x = src[i]; + *q++ = duk_lc_digits[x >> 4]; + *q++ = duk_lc_digits[x & 0x0f]; + } + + return q; +} +#else /* DUK_USE_HEX_FASTPATH */ +DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { + const duk_uint8_t *p; + const duk_uint8_t *p_end; + duk_uint8_t *q; + duk_small_uint_t x; + + p = src; + p_end = src + src_len; + q = dst; + while (p != p_end) { + x = *p++; + *q++ = duk_lc_digits[x >> 4]; + *q++ = duk_lc_digits[x & 0x0f]; + } + + return q; +} +#endif /* DUK_USE_HEX_FASTPATH */ + +DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) { + duk_hthread *thr; + duk_uint8_t *q; + duk_size_t space; + + thr = js_ctx->thr; + + DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ + DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); + + /* Buffer values are encoded in (lowercase) hex to make the + * binary data readable. Base64 or similar would be more + * compact but less readable, and the point of JX/JC + * variants is to be as useful to a programmer as possible. + */ + + /* The #ifdef clutter here needs to handle the three cases: + * (1) JX+JC, (2) JX only, (3) JC only. + */ + + /* Note: space must cater for both JX and JC. */ + space = 9 + buf_len * 2 + 2; + DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL); + DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */ + q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); + +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom) +#endif +#if defined(DUK_USE_JX) + { + *q++ = DUK_ASC_PIPE; + q = duk__enc_buffer_data_hex(buf_data, buf_len, q); + *q++ = DUK_ASC_PIPE; + + } +#endif +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + else +#endif +#if defined(DUK_USE_JC) + { + DUK_ASSERT(js_ctx->flag_ext_compatible); + DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */ + q += 9; + q = duk__enc_buffer_data_hex(buf_data, buf_len, q); + *q++ = DUK_ASC_DOUBLEQUOTE; + *q++ = DUK_ASC_RCURLY; + } +#endif + + DUK_BW_SET_PTR(thr, &js_ctx->bw, q); +} + +DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { + duk__enc_buffer_data(js_ctx, + (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), + (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); +} +#endif /* DUK_USE_JX || DUK_USE_JC */ + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { + char buf[64]; /* XXX: how to figure correct size? */ + const char *fmt; + + DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ + DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); + + DUK_MEMZERO(buf, sizeof(buf)); + + /* The #ifdef clutter here needs to handle the three cases: + * (1) JX+JC, (2) JX only, (3) JC only. + */ +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom) +#endif +#if defined(DUK_USE_JX) + { + fmt = ptr ? "(%p)" : "(null)"; + } +#endif +#if defined(DUK_USE_JX) && defined(DUK_USE_JC) + else +#endif +#if defined(DUK_USE_JC) + { + DUK_ASSERT(js_ctx->flag_ext_compatible); + fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}"; + } +#endif + + /* When ptr == NULL, the format argument is unused. */ + DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */ + DUK__EMIT_CSTR(js_ctx, buf); +} +#endif /* DUK_USE_JX || DUK_USE_JC */ + +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) +#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) +DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) { + DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj); + + if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) { + DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); + } else { + /* Handle both full and partial slice (as long as covered). */ + duk__enc_buffer_data(js_ctx, + (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj), + (duk_size_t) h_bufobj->length); + } +} +#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ +#endif /* DUK_USE_JX || DUK_USE_JC */ + +/* Indent helper. Calling code relies on js_ctx->recursion_depth also being + * directly related to indent depth. */ -DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top) { +#if defined(DUK_USE_PREFER_SIZE) +DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) { + DUK_ASSERT(js_ctx->h_gap != NULL); + DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ + + DUK__EMIT_1(js_ctx, 0x0a); + while (depth-- > 0) { + DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap); + } +} +#else /* DUK_USE_PREFER_SIZE */ +DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) { + const duk_uint8_t *gap_data; + duk_size_t gap_len; + duk_size_t avail_bytes; /* bytes of indent available for copying */ + duk_size_t need_bytes; /* bytes of indent still needed */ + duk_uint8_t *p_start; + duk_uint8_t *p; + + DUK_ASSERT(js_ctx->h_gap != NULL); + DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ + + DUK__EMIT_1(js_ctx, 0x0a); + if (DUK_UNLIKELY(depth == 0)) { + return; + } + + /* To handle deeper indents efficiently, make use of copies we've + * already emitted. In effect we can emit a sequence of 1, 2, 4, + * 8, etc copies, and then finish the last run. Byte counters + * avoid multiply with gap_len on every loop. + */ + + gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap); + gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap); + DUK_ASSERT(gap_len > 0); + + need_bytes = gap_len * depth; + p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes); + p_start = p; + + DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len); + p += gap_len; + avail_bytes = gap_len; + DUK_ASSERT(need_bytes >= gap_len); + need_bytes -= gap_len; + + while (need_bytes >= avail_bytes) { + DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes); + p += avail_bytes; + need_bytes -= avail_bytes; + avail_bytes <<= 1; + } + + DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */ + DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes); + p += need_bytes; + /*avail_bytes += need_bytes*/ + + DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p); +} +#endif /* DUK_USE_PREFER_SIZE */ + +/* Shared entry handling for object/array serialization. */ +DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { duk_context *ctx = (duk_context *) js_ctx->thr; duk_hobject *h_target; + duk_uint_fast32_t i, n; *entry_top = duk_get_top(ctx); duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK); - /* loop check */ + /* Loop check using a hybrid approach: a fixed-size visited[] array + * with overflow in a loop check object. + */ h_target = duk_get_hobject(ctx, -1); /* object or array */ DUK_ASSERT(h_target != NULL); - /* XXX: this check is very expensive, perhaps use a small - * array to make it faster for at least reasonably shallow - * objects? - */ - duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target); - duk_dup_top(ctx); /* -> [ ... voidp voidp ] */ - if (duk_has_prop(ctx, js_ctx->idx_loop)) { - DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT); + n = js_ctx->recursion_depth; + if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) { + n = DUK_JSON_ENC_LOOPARRAY; + } + for (i = 0; i < n; i++) { + if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) { + DUK_DD(DUK_DDPRINT("slow path loop detect")); + DUK_ERROR(js_ctx->thr, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT); + } + } + if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { + js_ctx->visiting[js_ctx->recursion_depth] = h_target; + } else { + duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target); + duk_dup_top(ctx); /* -> [ ... voidp voidp ] */ + if (duk_has_prop(ctx, js_ctx->idx_loop)) { + DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT); + } + duk_push_true(ctx); /* -> [ ... voidp true ] */ + duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */ } - duk_push_true(ctx); /* -> [ ... voidp true ] */ - duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */ - /* c recursion check */ + /* C recursion check. */ DUK_ASSERT(js_ctx->recursion_depth >= 0); DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); @@ -32851,71 +33771,34 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_hstring **h_s } js_ctx->recursion_depth++; - /* figure out indent and stepback */ - - *h_indent = NULL; - *h_stepback = NULL; - if (js_ctx->h_gap != NULL) { - DUK_ASSERT(js_ctx->h_indent != NULL); - - *h_stepback = js_ctx->h_indent; - duk_push_hstring(ctx, js_ctx->h_indent); - duk_push_hstring(ctx, js_ctx->h_gap); - duk_concat(ctx, 2); - js_ctx->h_indent = duk_get_hstring(ctx, -1); - *h_indent = js_ctx->h_indent; - DUK_ASSERT(js_ctx->h_indent != NULL); - - /* The new indent string is left at value stack top, and will - * be popped by the shared exit handler. - */ - } else { - DUK_ASSERT(js_ctx->h_indent == NULL); - } - DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T", (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop))); } /* Shared exit handling for object/array serialization. */ -DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, duk_idx_t *entry_top) { +DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { duk_context *ctx = (duk_context *) js_ctx->thr; duk_hobject *h_target; - DUK_UNREF(h_indent); - - if (js_ctx->h_gap != NULL) { - DUK_ASSERT(js_ctx->h_indent != NULL); - DUK_ASSERT(*h_stepback != NULL); - DUK_ASSERT(*h_indent != NULL); - - js_ctx->h_indent = *h_stepback; /* previous js_ctx->h_indent */ - - /* Note: we don't need to pop anything because the duk_set_top() - * at the end will take care of it. - */ - } else { - DUK_ASSERT(js_ctx->h_indent == NULL); - DUK_ASSERT(*h_stepback == NULL); - DUK_ASSERT(*h_indent == NULL); - } - - /* c recursion check */ + /* C recursion check. */ DUK_ASSERT(js_ctx->recursion_depth > 0); DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); js_ctx->recursion_depth--; - /* loop check */ + /* Loop check. */ h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */ DUK_ASSERT(h_target != NULL); - /* XXX: this check is very expensive */ - duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target); - duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */ + if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { + /* Previous entry was inside visited[], nothing to do. */ + } else { + duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target); + duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */ + } - /* restore stack top after unbalanced code paths */ + /* Restore stack top after unbalanced code paths. */ duk_set_top(ctx, *entry_top); DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T", @@ -32928,8 +33811,6 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_st */ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { duk_context *ctx = (duk_context *) js_ctx->thr; - duk_hstring *h_stepback; - duk_hstring *h_indent; duk_hstring *h_key; duk_idx_t entry_top; duk_idx_t idx_obj; @@ -32940,7 +33821,7 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1))); - duk__enc_objarr_entry(js_ctx, &h_stepback, &h_indent, &entry_top); + duk__enc_objarr_entry(js_ctx, &entry_top); idx_obj = entry_top - 1; @@ -32991,21 +33872,16 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { } else { DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); } - if (h_indent != NULL) { - DUK__EMIT_1(js_ctx, 0x0a); - DUK__EMIT_HSTR(js_ctx, h_indent); + if (js_ctx->h_gap != NULL) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); } h_key = duk_get_hstring(ctx, -2); DUK_ASSERT(h_key != NULL); - if (js_ctx->flag_avoid_key_quotes && !duk__enc_key_quotes_needed(h_key)) { - /* emit key as is */ - DUK__EMIT_HSTR(js_ctx, h_key); - } else { - duk__enc_quote_string(js_ctx, h_key); - } + duk__enc_key_autoquote(js_ctx, h_key); - if (h_indent != NULL) { + if (js_ctx->h_gap != NULL) { DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); } else { DUK__EMIT_1(js_ctx, DUK_ASC_COLON); @@ -33017,15 +33893,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { } if (!first) { - if (h_stepback != NULL) { - DUK_ASSERT(h_indent != NULL); - DUK__EMIT_1(js_ctx, 0x0a); - DUK__EMIT_HSTR(js_ctx, h_stepback); + if (js_ctx->h_gap != NULL) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); } } DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); - duk__enc_objarr_exit(js_ctx, &h_stepback, &h_indent, &entry_top); + duk__enc_objarr_exit(js_ctx, &entry_top); DUK_ASSERT_TOP(ctx, entry_top); } @@ -33036,8 +33911,6 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) { */ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { duk_context *ctx = (duk_context *) js_ctx->thr; - duk_hstring *h_stepback; - duk_hstring *h_indent; duk_idx_t entry_top; duk_idx_t idx_arr; duk_bool_t undef; @@ -33046,7 +33919,7 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T", (duk_tval *) duk_get_tval(ctx, -1))); - duk__enc_objarr_entry(js_ctx, &h_stepback, &h_indent, &entry_top); + duk__enc_objarr_entry(js_ctx, &entry_top); idx_arr = entry_top - 1; @@ -33056,16 +33929,16 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr); for (i = 0; i < arr_len; i++) { - DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, h_indent=%!O, h_stepback=%!O, index=%ld, arr_len=%ld", - (duk_tval *) duk_get_tval(ctx, idx_arr), (duk_heaphdr *) h_indent, - (duk_heaphdr *) h_stepback, (long) i, (long) arr_len)); + DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld", + (duk_tval *) duk_get_tval(ctx, idx_arr), + (long) i, (long) arr_len)); if (i > 0) { DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); } - if (h_indent != NULL) { - DUK__EMIT_1(js_ctx, 0x0a); - DUK__EMIT_HSTR(js_ctx, h_indent); + if (js_ctx->h_gap != NULL) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); } /* XXX: duk_push_uint_string() */ @@ -33082,15 +33955,14 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) { } if (arr_len > 0) { - if (h_stepback != NULL) { - DUK_ASSERT(h_indent != NULL); - DUK__EMIT_1(js_ctx, 0x0a); - DUK__EMIT_HSTR(js_ctx, h_stepback); + if (js_ctx->h_gap != NULL) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); } } DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); - duk__enc_objarr_exit(js_ctx, &h_stepback, &h_indent, &entry_top); + duk__enc_objarr_exit(js_ctx, &entry_top); DUK_ASSERT_TOP(ctx, entry_top); } @@ -33290,35 +34162,7 @@ DUK_LOCAL void duk__enc_value2(duk_json_enc_ctx *js_ctx) { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) /* When JX/JC not in use, duk__enc_value1 will block pointer values. */ case DUK_TAG_POINTER: { - char buf[64]; /* XXX: how to figure correct size? */ - const char *fmt; - void *ptr = DUK_TVAL_GET_POINTER(tv); - - DUK_MEMZERO(buf, sizeof(buf)); - - /* The #ifdef clutter here needs to handle the three cases: - * (1) JX+JC, (2) JX only, (3) JC only. - */ -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom) -#endif -#if defined(DUK_USE_JX) - { - fmt = ptr ? "(%p)" : "(null)"; - } -#endif -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - else -#endif -#if defined(DUK_USE_JC) - { - fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}"; - } -#endif - - /* When ptr == NULL, the format argument is unused. */ - DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */ - DUK__EMIT_CSTR(js_ctx, buf); + duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); break; } #endif /* DUK_USE_JX || DUK_USE_JC */ @@ -33350,59 +34194,7 @@ DUK_LOCAL void duk__enc_value2(duk_json_enc_ctx *js_ctx) { #if defined(DUK_USE_JX) || defined(DUK_USE_JC) /* When JX/JC not in use, duk__enc_value1 will block buffer values. */ case DUK_TAG_BUFFER: { - /* Buffer values are encoded in (lowercase) hex to make the - * binary data readable. Base64 or similar would be more - * compact but less readable, and the point of JX/JC - * variants is to be as useful to a programmer as possible. - */ - - /* The #ifdef clutter here needs to handle the three cases: - * (1) JX+JC, (2) JX only, (3) JC only. - */ -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - if (js_ctx->flag_ext_custom) -#endif -#if defined(DUK_USE_JX) - { - duk_uint8_t *p, *p_end; - duk_small_uint_t x; - duk_hbuffer *h; - duk_uint8_t *q; - duk_size_t space; - - h = DUK_TVAL_GET_BUFFER(tv); - DUK_ASSERT(h != NULL); - p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); - p_end = p + DUK_HBUFFER_GET_SIZE(h); - - space = 1 + DUK_HBUFFER_GET_SIZE(h) * 2 + 1; - DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL); - DUK_ASSERT((space - 2) / 2 == DUK_HBUFFER_GET_SIZE(h)); /* overflow not possible, buffer limits */ - q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); - - *q++ = DUK_ASC_PIPE; - while (p < p_end) { - x = *p++; - *q++ = duk_lc_digits[(x >> 4) & 0x0f]; - *q++ = duk_lc_digits[x & 0x0f]; - } - *q++ = DUK_ASC_PIPE; - - DUK_BW_SET_PTR(thr, &js_ctx->bw, q); - } -#endif -#if defined(DUK_USE_JX) && defined(DUK_USE_JC) - else -#endif -#if defined(DUK_USE_JC) - { - DUK_ASSERT(js_ctx->flag_ext_compatible); - duk_hex_encode(ctx, -1); - DUK__EMIT_CSTR(js_ctx, "{\"_buf\":"); - duk__enc_quote_string(js_ctx, duk_require_hstring(ctx, -1)); - DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); - } -#endif + duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); break; } #endif /* DUK_USE_JX || DUK_USE_JC */ @@ -33464,6 +34256,11 @@ DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) { /* * JSON.stringify() fast path + * + * Otherwise supports full JSON, JX, and JC features, but bails out on any + * possible side effect which might change the value being serialized. The + * fast path can take advantage of the fact that the value being serialized + * is unchanged so that we can walk directly through property tables etc. */ #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) @@ -33474,19 +34271,22 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du DUK_ASSERT(js_ctx != NULL); DUK_ASSERT(js_ctx->thr != NULL); -#if defined(DUK_USE_JX) - DUK_ASSERT(js_ctx->flag_ext_custom == 0); -#endif -#if defined(DUK_USE_JC) - DUK_ASSERT(js_ctx->flag_ext_compatible == 0); -#endif restart_match: DUK_ASSERT(tv != NULL); switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_UNDEFINED: { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) { + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); + break; + } else { + goto emit_undefined; + } +#else goto emit_undefined; +#endif } case DUK_TAG_NULL: { DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); @@ -33509,7 +34309,8 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du duk_hobject *obj; duk_tval *tv_val; duk_bool_t emitted = 0; - duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef, c_object; + duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef, + c_func, c_bufobj, c_object; /* For objects JSON.stringify() only looks for own, enumerable * properties which is nice for the fast path here. @@ -33526,12 +34327,16 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du * execution time for input data with a lot of small objects!). */ - obj = DUK_TVAL_GET_OBJECT(tv); - DUK_ASSERT(obj != NULL); + /* XXX: for real world code, could just ignore array inheritance + * and only look at array own properties. + */ /* We rely on a few object flag / class number relationships here, * assert for them. */ + + obj = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(obj != NULL); DUK_ASSERT_HOBJECT_VALID(obj); /* Once recursion depth is increased, exit path must decrease @@ -33546,7 +34351,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du } for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) { - if (js_ctx->visiting[i] == obj) { + if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) { DUK_DD(DUK_DDPRINT("fast path loop detect")); DUK_ERROR(js_ctx->thr, DUK_ERR_TYPE_ERROR, DUK_STR_CYCLIC_INPUT); } @@ -33566,6 +34371,9 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du * If an object is a Proxy we also can't avoid side effects * so abandon. */ + /* XXX: non-callable .toJSON() doesn't need to cause an abort + * but does at the moment, probably not worth fixing. + */ if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) || DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) { DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path")); @@ -33577,15 +34385,38 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du * should be in order of relevancy. */ + /* XXX: move masks to js_ctx? they don't change during one + * fast path invocation. + */ DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31); - c_all = DUK_HOBJECT_CMASK_ALL; - c_array = DUK_HOBJECT_CMASK_ARRAY; - c_unbox = DUK_HOBJECT_CMASK_NUMBER | - DUK_HOBJECT_CMASK_STRING | - DUK_HOBJECT_CMASK_BOOLEAN; - c_undef = DUK_HOBJECT_CMASK_FUNCTION | - DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS; - c_object = c_all & ~(c_array | c_unbox | c_undef); +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom_or_compatible) { + c_all = DUK_HOBJECT_CMASK_ALL; + c_array = DUK_HOBJECT_CMASK_ARRAY; + c_unbox = DUK_HOBJECT_CMASK_NUMBER | + DUK_HOBJECT_CMASK_STRING | + DUK_HOBJECT_CMASK_BOOLEAN | + DUK_HOBJECT_CMASK_POINTER; + c_func = DUK_HOBJECT_CMASK_FUNCTION; + c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS; + c_undef = 0; + c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef); + } + else +#endif + { + c_all = DUK_HOBJECT_CMASK_ALL; + c_array = DUK_HOBJECT_CMASK_ARRAY; + c_unbox = DUK_HOBJECT_CMASK_NUMBER | + DUK_HOBJECT_CMASK_STRING | + DUK_HOBJECT_CMASK_BOOLEAN; + c_func = 0; + c_bufobj = 0; + c_undef = DUK_HOBJECT_CMASK_FUNCTION | + DUK_HOBJECT_CMASK_POINTER | + DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS; + c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef); + } c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj); if (c_bit & c_object) { @@ -33626,8 +34457,16 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i); prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); - duk__enc_quote_string(js_ctx, k); - DUK__EMIT_1(js_ctx, DUK_ASC_COLON); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + duk__enc_key_autoquote(js_ctx, k); + DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); + } else { + duk__enc_key_autoquote(js_ctx, k); + DUK__EMIT_1(js_ctx, DUK_ASC_COLON); + } + if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) { DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon")); DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size); @@ -33643,7 +34482,12 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du */ if (emitted) { + DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); + } } DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); } else if (c_bit & c_array) { @@ -33675,6 +34519,10 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i); + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth); + } + if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) { /* Gap in array; check for inherited property, * bail out if one exists. This should be enough @@ -33710,11 +34558,16 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du } if (emitted) { + DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ + if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { + DUK_ASSERT(js_ctx->recursion_depth >= 1); + duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1); + } } DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); } else if (c_bit & c_unbox) { - /* These three boxed types are required to go through + /* Certain boxed types are required to go through * automatic unboxing. Rely on internal value being * sane (to avoid infinite recursion). */ @@ -33726,21 +34579,22 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du DUK_ASSERT(tv_internal != NULL); DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) || DUK_TVAL_IS_NUMBER(tv_internal) || - DUK_TVAL_IS_BOOLEAN(tv_internal)); + DUK_TVAL_IS_BOOLEAN(tv_internal) || + DUK_TVAL_IS_POINTER(tv_internal)); - /* XXX: for JX/JC, special handling for Pointer, and Buffer? */ tv = tv_internal; + DUK_ASSERT(js_ctx->recursion_depth > 0); + js_ctx->recursion_depth--; /* required to keep recursion depth correct */ goto restart_match; +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + } else if (c_bit & c_func) { + DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); + } else if (c_bit & c_bufobj) { + duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj); +#endif } else { DUK_ASSERT((c_bit & c_undef) != 0); - /* Function objects are treated as "undefined" by JSON. - * - * The slow path replaces a buffer object automatically with - * the binary data which then gets treated like "undefined". - * Since we don't support buffers here now, treat as "undefined". - */ - /* Must decrease recursion depth before returning. */ DUK_ASSERT(js_ctx->recursion_depth > 0); DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); @@ -33754,13 +34608,34 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du break; } case DUK_TAG_BUFFER: { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom_or_compatible) { + duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv)); + break; + } else { + goto emit_undefined; + } +#else goto emit_undefined; +#endif } case DUK_TAG_POINTER: { +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + if (js_ctx->flag_ext_custom_or_compatible) { + duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); + break; + } else { + goto emit_undefined; + } +#else goto emit_undefined; +#endif } case DUK_TAG_LIGHTFUNC: { /* A lightfunc might also inherit a .toJSON() so just bail out. */ + /* XXX: Could just lookup .toJSON() and continue in fast path, + * as it would almost never be defined. + */ DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path")); goto abort_fastpath; } @@ -33868,12 +34743,15 @@ void duk_bi_json_parse_helper(duk_context *ctx, */ js_ctx->flags = flags; -#ifdef DUK_USE_JX +#if defined(DUK_USE_JX) js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM; #endif -#ifdef DUK_USE_JC +#if defined(DUK_USE_JC) js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; #endif +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); +#endif h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */ DUK_ASSERT(h_text != NULL); @@ -33882,9 +34760,9 @@ void duk_bi_json_parse_helper(duk_context *ctx, * valid and points to the string NUL terminator (which is always * guaranteed for duk_hstrings. */ - js_ctx->p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text); + js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text); js_ctx->p = js_ctx->p_start; - js_ctx->p_end = ((duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) + + js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) + DUK_HSTRING_GET_BYTELEN(h_text); DUK_ASSERT(*(js_ctx->p_end) == 0x00); @@ -33969,7 +34847,6 @@ void duk_bi_json_stringify_helper(duk_context *ctx, #ifdef DUK_USE_EXPLICIT_NULL_INIT js_ctx->h_replacer = NULL; js_ctx->h_gap = NULL; - js_ctx->h_indent = NULL; #endif js_ctx->idx_proplist = -1; @@ -33986,6 +34863,9 @@ void duk_bi_json_stringify_helper(duk_context *ctx, #ifdef DUK_USE_JC js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; #endif +#if defined(DUK_USE_JX) || defined(DUK_USE_JC) + js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); +#endif /* The #ifdef clutter here handles the JX/JC enable/disable * combinations properly. @@ -34131,15 +35011,9 @@ void duk_bi_json_stringify_helper(duk_context *ctx, /* if gap is empty, behave as if not given at all */ if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) { js_ctx->h_gap = NULL; - } else { - /* set 'indent' only if it will actually increase */ - js_ctx->h_indent = DUK_HTHREAD_STRING_EMPTY_STRING(thr); } } - DUK_ASSERT((js_ctx->h_gap == NULL && js_ctx->h_indent == NULL) || - (js_ctx->h_gap != NULL && js_ctx->h_indent != NULL)); - /* [ ... buf loop (proplist) (gap) ] */ /* @@ -34148,15 +35022,8 @@ void duk_bi_json_stringify_helper(duk_context *ctx, */ #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) - /* For now fast path is limited to plain JSON (no JX/JC). This would - * be easy to fix but must go through value type handling in the fast - * path. - */ - if (flags == 0 && - js_ctx->h_replacer == NULL && - js_ctx->idx_proplist == -1 && - js_ctx->h_gap == NULL && - js_ctx->h_indent == NULL) { + if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ + js_ctx->idx_proplist == -1) { /* proplist is very rare */ duk_int_t pcall_rc; #ifdef DUK_USE_MARK_AND_SWEEP duk_small_uint_t prev_mark_and_sweep_base_flags; @@ -34206,7 +35073,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx, * kept because we'll probably need at least as much as we've * allocated so far. */ - DUK_DD(DUK_DDPRINT("fast path failed, serialize using slow path instead")); + DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead")); DUK_BW_RESET_SIZE(thr, &js_ctx->bw); js_ctx->recursion_depth = 0; } @@ -34221,13 +35088,12 @@ void duk_bi_json_stringify_helper(duk_context *ctx, duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, " - "proplist=%!T, gap=%!O, indent=%!O, holder=%!T", + "proplist=%!T, gap=%!O, holder=%!T", (unsigned long) js_ctx->flags, (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop), (duk_heaphdr *) js_ctx->h_replacer, (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL), (duk_heaphdr *) js_ctx->h_gap, - (duk_heaphdr *) js_ctx->h_indent, (duk_tval *) duk_get_tval(ctx, -1))); /* serialize the wrapper with empty string key */ @@ -34241,28 +35107,20 @@ void duk_bi_json_stringify_helper(duk_context *ctx, undef = duk__enc_value1(js_ctx, idx_holder); /* [ ... holder key ] -> [ ... holder key val ] */ DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, " - "proplist=%!T, gap=%!O, indent=%!O, holder=%!T", + "proplist=%!T, gap=%!O, holder=%!T", (unsigned long) js_ctx->flags, (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop), (duk_heaphdr *) js_ctx->h_replacer, (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL), (duk_heaphdr *) js_ctx->h_gap, - (duk_heaphdr *) js_ctx->h_indent, (duk_tval *) duk_get_tval(ctx, -3))); if (undef) { - /* - * Result is undefined - */ - + /* Result is undefined. */ duk_push_undefined(ctx); } else { - /* - * Finish and convert buffer to result string - */ - + /* Finish and convert buffer to result string. */ duk__enc_value2(js_ctx); /* [ ... key val ] -> [ ... ] */ - DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); } @@ -34560,18 +35418,18 @@ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) { DUK_ASSERT(buf != NULL); p = buf; - DUK_MEMCPY((void *) p, (void *) date_buf, date_len); + DUK_MEMCPY((void *) p, (const void *) date_buf, (size_t) date_len); p += date_len; *p++ = (duk_uint8_t) DUK_ASC_SPACE; q = duk__log_level_strings + (entry_lev * 3); - DUK_MEMCPY((void *) p, (void *) q, (duk_size_t) 3); + DUK_MEMCPY((void *) p, (const void *) q, (size_t) 3); p += 3; *p++ = (duk_uint8_t) DUK_ASC_SPACE; arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len); - DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len); + DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len); p += arg_len; *p++ = (duk_uint8_t) DUK_ASC_COLON; @@ -34581,7 +35439,7 @@ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) { arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len); DUK_ASSERT(arg_str != NULL); - DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len); + DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len); p += arg_len; } DUK_ASSERT(buf + tot_len == p); @@ -35692,6 +36550,12 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) { } } + /* XXX: missing trap result validation for non-configurable target keys + * (must be present), for non-extensible target all target keys must be + * present and no extra keys can be present. + * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys + */ + /* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result) * should be filtered so that only enumerable keys remain. Enumerability * should be checked with [[GetOwnProperty]] on the original object @@ -35725,31 +36589,8 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) { } DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) { - duk_hthread *thr = (duk_hthread *) ctx; - duk_push_this(ctx); - duk_push_string(ctx, "[object "); - - if (duk_is_undefined(ctx, -2)) { - duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_UNDEFINED); - } else if (duk_is_null(ctx, -2)) { - duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_NULL); - } else { - duk_hobject *h_this; - duk_hstring *h_classname; - - duk_to_object(ctx, -2); - h_this = duk_get_hobject(ctx, -2); - DUK_ASSERT(h_this != NULL); - - h_classname = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_this); - DUK_ASSERT(h_classname != NULL); - - duk_push_hstring(ctx, h_classname); - } - - duk_push_string(ctx, "]"); - duk_concat(ctx, 3); + duk_to_object_class_string_top(ctx); return 1; } @@ -36534,7 +37375,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */ - if (DUK_MEMCMP(p, q_start, (duk_size_t) q_blen) == 0) { + if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { duk_push_int(ctx, cpos); return 1; } @@ -36744,7 +37585,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) { while (p <= p_end) { DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); - if (DUK_MEMCMP((void *) p, (void *) q_start, (size_t) q_blen) == 0) { + if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { duk_dup(ctx, 0); h_match = duk_get_hstring(ctx, -1); DUK_ASSERT(h_match != NULL); @@ -37129,7 +37970,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) { while (p <= p_end) { DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */ - if (DUK_MEMCMP((void *) p, (void *) q_start, (duk_size_t) q_blen) == 0) { + if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { /* never an empty match, so step 13.c.iii can't be triggered */ goto found; } @@ -37440,9 +38281,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) prefix_len = (h1_len <= h2_len ? h1_len : h2_len); /* Zero size compare not an issue with DUK_MEMCMP. */ - rc = (duk_small_int_t) DUK_MEMCMP((const char *) DUK_HSTRING_GET_DATA(h1), - (const char *) DUK_HSTRING_GET_DATA(h2), - prefix_len); + rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1), + (const void *) DUK_HSTRING_GET_DATA(h2), + (size_t) prefix_len); if (rc < 0) { ret = -1; @@ -37639,6 +38480,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) { /* lj value1: value */ DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top); DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */ + DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1); thr->heap->lj.iserror = is_error; @@ -37755,6 +38597,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) { /* lj value1: value */ DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */ + DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1); thr->heap->lj.iserror = is_error; @@ -37792,7 +38635,7 @@ DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) { #ifdef DUK_USE_DEBUG -DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk_size_t length) { +DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) { duk_size_t avail; duk_size_t copylen; @@ -37808,11 +38651,11 @@ DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk } DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) { - duk_fb_put_bytes(fb, &x, 1); + duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1); } DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) { - duk_fb_put_bytes(fb, (duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x)); + duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x)); } DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) { @@ -39169,24 +40012,46 @@ typedef union { * Detach handling */ -#define DUK__SET_CONN_BROKEN(thr) do { \ +#define DUK__SET_CONN_BROKEN(thr,reason) do { \ /* For now shared handler is fine. */ \ - duk_debug_do_detach((thr)->heap); \ + duk__debug_do_detach1((thr)->heap, (reason)); \ } while (0) -DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) { - /* Can be called muliple times with no harm. */ +DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) { + /* Can be called multiple times with no harm. Mark the transport + * bad (dbg_read_cb == NULL) and clear state except for the detached + * callback and the udata field. The detached callback is delayed + * to the message loop so that it can be called between messages; + * this avoids corner cases related to immediate debugger reattach + * inside the detached callback. + */ + + if (heap->dbg_detaching) { + return; + } + + DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken")); + + heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */ + + if (heap->dbg_write_cb != NULL) { + duk_hthread *thr; + + thr = heap->heap_thread; + DUK_ASSERT(thr != NULL); + + duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING); + duk_debug_write_int(thr, reason); + duk_debug_write_eom(thr); + } heap->dbg_read_cb = NULL; heap->dbg_write_cb = NULL; heap->dbg_peek_cb = NULL; heap->dbg_read_flush_cb = NULL; heap->dbg_write_flush_cb = NULL; - if (heap->dbg_detached_cb) { - heap->dbg_detached_cb(heap->dbg_udata); - } - heap->dbg_detached_cb = NULL; - heap->dbg_udata = NULL; + /* heap->dbg_detached_cb: keep */ + /* heap->dbg_udata: keep */ heap->dbg_processing = 0; heap->dbg_paused = 0; heap->dbg_state_dirty = 0; @@ -39195,6 +40060,7 @@ DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) { heap->dbg_step_thread = NULL; heap->dbg_step_csindex = 0; heap->dbg_step_startline = 0; + heap->dbg_have_next_byte = 0; /* Ensure there are no stale active breakpoint pointers. * Breakpoint list is currently kept - we could empty it @@ -39206,6 +40072,34 @@ DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) { heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; } +DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) { + duk_debug_detached_function detached_cb; + void *detached_udata; + + /* Safe to call multiple times. */ + + detached_cb = heap->dbg_detached_cb; + detached_udata = heap->dbg_udata; + heap->dbg_detached_cb = NULL; + heap->dbg_udata = NULL; + + if (detached_cb) { + /* Careful here: state must be wiped before the call + * so that we can cleanly handle a re-attach from + * inside the callback. + */ + DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb")); + detached_cb(detached_udata); + } + + heap->dbg_detaching = 0; +} + +DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) { + duk__debug_do_detach1(heap, 0); + duk__debug_do_detach2(heap); +} + /* * Debug connection peek and flush primitives */ @@ -39295,6 +40189,21 @@ DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) { * Debug connection read primitives */ +/* Peek ahead in the stream one byte. */ +DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) { + /* It is important not to call this if the last byte read was an EOM. + * Reading ahead in this scenario would cause unnecessary blocking if + * another message is not available. + */ + + duk_uint8_t x; + + x = duk_debug_read_byte(thr); + thr->heap->dbg_have_next_byte = 1; + thr->heap->dbg_next_byte = x; + return x; +} + /* Read fully. */ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) { duk_heap *heap; @@ -39311,7 +40220,12 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_ goto fail; } + /* NOTE: length may be zero */ p = data; + if (length >= 1 && heap->dbg_have_next_byte) { + heap->dbg_have_next_byte = 0; + *p++ = heap->dbg_next_byte; + } for (;;) { left = (duk_size_t) ((data + length) - p); if (left == 0) { @@ -39324,8 +40238,9 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_ #endif got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left); if (got == 0 || got > left) { + heap->dbg_write_cb = NULL; /* squelch further writes */ DUK_D(DUK_DPRINT("connection error during read, return zero data")); - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 1); goto fail; } p += got; @@ -39337,28 +40252,10 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_ } DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) { - duk_heap *heap; - duk_size_t got; duk_uint8_t x; - DUK_ASSERT(thr != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - if (heap->dbg_read_cb == NULL) { - DUK_D(DUK_DPRINT("attempt to read 1 bytes in detached state, return zero data")); - return 0; - } - x = 0; /* just in case callback is broken and won't write 'x' */ - DUK_ASSERT(heap->dbg_read_cb != NULL); - got = heap->dbg_read_cb(heap->dbg_udata, (char *) (&x), 1); - if (got != 1) { - DUK_D(DUK_DPRINT("connection error during read, return zero data")); - DUK__SET_CONN_BROKEN(thr); - return 0; - } - + duk_debug_read_bytes(thr, &x, 1); return x; } @@ -39405,7 +40302,7 @@ DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) { } DUK_D(DUK_DPRINT("debug connection error: failed to decode int")); - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 1); return 0; } @@ -39450,7 +40347,7 @@ DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) { fail: DUK_D(DUK_DPRINT("debug connection error: failed to decode int")); - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 1); duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* always push some string */ return duk_require_hstring(ctx, -1); } @@ -39466,9 +40363,9 @@ DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_ return duk_require_hbuffer(ctx, -1); } -DUK_LOCAL const void *duk__debug_read_pointer_raw(duk_hthread *thr) { +DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) { duk_small_uint_t x; - volatile duk__ptr_union pu; + duk__ptr_union pu; DUK_ASSERT(thr != NULL); @@ -39480,12 +40377,12 @@ DUK_LOCAL const void *duk__debug_read_pointer_raw(duk_hthread *thr) { #if defined(DUK_USE_INTEGER_LE) duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu)); #endif - return (const void *) pu.p; + return (void *) pu.p; fail: DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer")); - DUK__SET_CONN_BROKEN(thr); - return (const void *) NULL; + DUK__SET_CONN_BROKEN(thr, 1); + return (void *) NULL; } DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) { @@ -39568,9 +40465,9 @@ DUK_INTERNAL void duk_debug_read_tval(duk_hthread *thr) { DUK_D(DUK_DPRINT("reading object values unimplemented")); goto fail; case 0x1c: { - const void *ptr; + void *ptr; ptr = duk__debug_read_pointer_raw(thr); - duk_push_pointer(thr, (void *) ptr); + duk_push_pointer(thr, ptr); break; } case 0x1d: @@ -39592,7 +40489,7 @@ DUK_INTERNAL void duk_debug_read_tval(duk_hthread *thr) { fail: DUK_D(DUK_DPRINT("debug connection error: failed to decode tval")); - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 1); } /* @@ -39636,8 +40533,9 @@ DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *dat #endif got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left); if (got == 0 || got > left) { + heap->dbg_write_cb = NULL; /* squelch further writes */ DUK_D(DUK_DPRINT("connection error during write")); - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 1); return; } p += got; @@ -39661,7 +40559,7 @@ DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) { got = heap->dbg_write_cb(heap->dbg_udata, (const char *) (&x), 1); if (got != 1) { DUK_D(DUK_DPRINT("connection error during write")); - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 1); } } @@ -39775,9 +40673,9 @@ DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) { (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0)); } -DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, const void *ptr, duk_uint8_t ibyte) { +DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) { duk_uint8_t buf[2]; - volatile duk__ptr_union pu; + duk__ptr_union pu; DUK_ASSERT(thr != NULL); DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16); @@ -39793,19 +40691,19 @@ DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, const void *ptr, d duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu)); } -DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, const void *ptr) { +DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) { duk__debug_write_pointer_raw(thr, ptr, 0x1c); } #if defined(DUK_USE_DEBUGGER_DUMPHEAP) DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) { - duk__debug_write_pointer_raw(thr, (const void *) h, 0x1e); + duk__debug_write_pointer_raw(thr, (void *) h, 0x1e); } #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) { duk_uint8_t buf[3]; - volatile duk__ptr_union pu; + duk__ptr_union pu; DUK_ASSERT(thr != NULL); DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16); @@ -39847,7 +40745,7 @@ DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) { duk_debug_write_byte(thr, DUK_TVAL_GET_BOOLEAN(tv) ? 0x18 : 0x19); break; case DUK_TAG_POINTER: - duk_debug_write_pointer(thr, (const void *) DUK_TVAL_GET_POINTER(tv)); + duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv)); break; case DUK_TAG_LIGHTFUNC: DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags); @@ -40113,7 +41011,7 @@ DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) { return 0; fail: - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 1); return 1; /* Pretend like we got EOM */ } @@ -40128,6 +41026,10 @@ DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) { /* * Process incoming debug requests + * + * Individual request handlers can push temporaries on the value stack and + * rely on duk__debug_process_message() to restore the value stack top + * automatically. */ DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) { @@ -40217,7 +41119,6 @@ DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) { } DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) { - duk_context *ctx = (duk_context *) thr; duk_hstring *filename; duk_uint32_t linenumber; duk_small_int_t idx; @@ -40235,7 +41136,6 @@ DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) { } else { duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint"); } - duk_pop(ctx); } DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) { @@ -40257,16 +41157,27 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) { duk_context *ctx = (duk_context *) thr; duk_hstring *str; duk_bool_t rc; + duk_int32_t level; DUK_UNREF(heap); DUK_D(DUK_DPRINT("debug command GetVar")); str = duk_debug_read_hstring(thr); /* push to stack */ DUK_ASSERT(str != NULL); + if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) { + level = duk_debug_read_int(thr); /* optional callstack level */ + if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) { + DUK_D(DUK_DPRINT("invalid callstack level for GetVar")); + duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level"); + return; + } + } else { + level = -1; + } if (thr->callstack_top > 0) { rc = duk_js_getvar_activation(thr, - thr->callstack + thr->callstack_top - 1, + thr->callstack + thr->callstack_top + level, str, 0); } else { @@ -40283,12 +41194,10 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) { duk_debug_write_int(thr, 1); DUK_ASSERT(duk_get_tval(ctx, -2) != NULL); duk_debug_write_tval(thr, duk_get_tval(ctx, -2)); - duk_pop_2(ctx); } else { duk_debug_write_int(thr, 0); duk_debug_write_unused(thr); } - duk_pop(ctx); duk_debug_write_eom(thr); } @@ -40296,6 +41205,7 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) { duk_context *ctx = (duk_context *) thr; duk_hstring *str; duk_tval *tv; + duk_int32_t level; DUK_UNREF(heap); DUK_D(DUK_DPRINT("debug command PutVar")); @@ -40305,17 +41215,26 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) { duk_debug_read_tval(thr); /* push to stack */ tv = duk_get_tval(ctx, -1); DUK_ASSERT(tv != NULL); + if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) { + level = duk_debug_read_int(thr); /* optional callstack level */ + if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) { + DUK_D(DUK_DPRINT("invalid callstack level for PutVar")); + duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level"); + return; + } + } else { + level = -1; + } if (thr->callstack_top > 0) { duk_js_putvar_activation(thr, - thr->callstack + thr->callstack_top - 1, + thr->callstack + thr->callstack_top + level, str, tv, 0); } else { DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar")); } - duk_pop_2(ctx); /* XXX: Current putvar implementation doesn't have a success flag, * add one and send to debug client? @@ -40376,15 +41295,28 @@ DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) { duk_context *ctx = (duk_context *) thr; duk_activation *curr_act; + duk_int32_t level; duk_hstring *varname; DUK_UNREF(heap); - duk_debug_write_reply(thr); - if (thr->callstack_top == 0) { - goto callstack_empty; + if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) { + level = duk_debug_read_int(thr); /* optional callstack level */ + if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) { + DUK_D(DUK_DPRINT("invalid callstack level for GetLocals")); + duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level"); + return; + } + duk_debug_write_reply(thr); + } else { + duk_debug_write_reply(thr); + if (thr->callstack_top == 0) { + goto callstack_empty; + } + level = -1; } - curr_act = thr->callstack + thr->callstack_top - 1; + + curr_act = thr->callstack + thr->callstack_top + level; /* XXX: several nice-to-have improvements here: * - Use direct reads avoiding value stack operations @@ -40406,11 +41338,9 @@ DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) { duk_debug_write_tval(thr, duk_get_tval(ctx, -2)); duk_pop_3(ctx); /* -> [ ... func varmap enum ] */ } - duk_pop(ctx); } else { DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore")); } - duk_pop_2(ctx); callstack_empty: duk_debug_write_eom(thr); @@ -40418,51 +41348,62 @@ DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) { DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) { duk_context *ctx = (duk_context *) thr; - duk_small_uint_t call_flags; duk_int_t call_ret; duk_small_int_t eval_err; -#if defined(DUK_USE_ASSERTIONS) - duk_idx_t entry_top; -#endif + duk_int32_t level; DUK_UNREF(heap); DUK_D(DUK_DPRINT("debug command Eval")); - /* The eval code must be executed within the current (topmost) - * activation. For now, use global object eval() function, with - * the eval considered a 'direct call to eval'. + /* The eval code is executed within the lexical environment of a specified + * activation. For now, use global object eval() function, with the eval + * considered a 'direct call to eval'. + * + * Callstack level for debug commands only affects scope -- the callstack + * as seen by, e.g. Duktape.act() will be the same regardless. */ -#if defined(DUK_USE_ASSERTIONS) - entry_top = duk_get_top(ctx); -#endif - - duk_push_c_function(ctx, duk_bi_global_object_eval, 1 /*nargs*/); + /* nargs == 2 so we can pass a callstack level to eval(). */ + duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/); duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */ + (void) duk_debug_read_hstring(thr); + if (duk_debug_peek_byte(thr) != DUK_DBG_MARKER_EOM) { + level = duk_debug_read_int(thr); /* optional callstack level */ + if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) { + DUK_D(DUK_DPRINT("invalid callstack level for Eval")); + duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level"); + return; + } + } + else { + level = -1; + } + DUK_ASSERT(level < 0 && -level <= (duk_int32_t) thr->callstack_top); + duk_push_int(ctx, level - 1); /* compensate for eval() call */ - /* [ ... eval "eval" eval_input ] */ + /* [ ... eval "eval" eval_input level ] */ call_flags = DUK_CALL_FLAG_PROTECTED; - if (thr->callstack_top >= 1) { + if (thr->callstack_top >= (duk_size_t) -level) { duk_activation *act; duk_hobject *fun; - act = thr->callstack + thr->callstack_top - 1; + act = thr->callstack + thr->callstack_top + level; fun = DUK_ACT_GET_FUNC(act); if (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) { /* Direct eval requires that there's a current * activation and it is an Ecmascript function. * When Eval is executed from e.g. cooperate API - * call we'll need to an indirect eval instead. + * call we'll need to do an indirect eval instead. */ call_flags |= DUK_CALL_FLAG_DIRECT_EVAL; } } - call_ret = duk_handle_call(thr, 1 /*num_stack_args*/, call_flags); + call_ret = duk_handle_call(thr, 2 /*num_stack_args*/, call_flags); if (call_ret == DUK_EXEC_SUCCESS) { eval_err = 0; @@ -40483,9 +41424,6 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) { DUK_ASSERT(duk_get_tval(ctx, -1) != NULL); duk_debug_write_tval(thr, duk_get_tval(ctx, -1)); duk_debug_write_eom(thr); - duk_pop(ctx); - - DUK_ASSERT(duk_get_top(ctx) == entry_top); } DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) { @@ -40496,7 +41434,7 @@ DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) { duk_debug_write_eom(thr); DUK_D(DUK_DPRINT("debug connection detached, mark broken")); - DUK__SET_CONN_BROKEN(thr); + DUK__SET_CONN_BROKEN(thr, 0); /* not an error */ } #if defined(DUK_USE_DEBUGGER_DUMPHEAP) @@ -40716,17 +41654,24 @@ DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) duk_debug_write_eom(thr); } +/* Process one debug message. Automatically restore value stack top to its + * entry value, so that individual message handlers don't need exact value + * stack handling which is convenient. + */ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) { duk_context *ctx = (duk_context *) thr; duk_heap *heap; duk_uint8_t x; duk_int32_t cmd; + duk_idx_t entry_top; DUK_ASSERT(thr != NULL); heap = thr->heap; DUK_ASSERT(heap != NULL); DUK_UNREF(ctx); + entry_top = duk_get_top(ctx); + x = duk_debug_read_byte(thr); switch (x) { case DUK_DBG_MARKER_REQUEST: { @@ -40787,6 +41732,10 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) { break; } case DUK_DBG_CMD_DETACH: { + /* The actual detached_cb call is postponed to message loop so + * we don't need any special precautions here (just skip to EOM + * on the already closed connection). + */ duk__debug_handle_detach(thr, heap); break; } @@ -40825,11 +41774,15 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) { } } /* switch initial byte */ + DUK_ASSERT(duk_get_top(ctx) >= entry_top); + duk_set_top(ctx, entry_top); duk__debug_skip_to_eom(thr); return; fail: - DUK__SET_CONN_BROKEN(thr); + DUK_ASSERT(duk_get_top(ctx) >= entry_top); + duk_set_top(ctx, entry_top); + DUK__SET_CONN_BROKEN(thr, 1); return; } @@ -40939,6 +41892,17 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t } duk__debug_process_message(thr); + + if (thr->heap->dbg_read_cb == NULL) { + /* Became detached during message handling (perhaps because + * of an error or by an explicit Detach). Call detached + * callback here, between messages, to avoid confusing the + * broken connection and a possible replacement (which may + * be provided by an instant reattach inside the detached + * callback). + */ + duk__debug_do_detach2(thr->heap); + } if (thr->heap->dbg_state_dirty) { /* Executed something that may have affected status, * resend. @@ -41025,8 +41989,8 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_ move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1); if (move_size > 0) { DUK_MEMMOVE((void *) b, - (void *) (b + 1), - move_size); + (const void *) (b + 1), + (size_t) move_size); } heap->dbg_breakpoint_count--; heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; @@ -41201,10 +42165,10 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c #endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */ /* - * Add tracedata to an error on the stack top. + * Add ._Tracedata to an error on the stack top. */ -#ifdef DUK_USE_TRACEBACKS +#if defined(DUK_USE_TRACEBACKS) DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) { duk_context *ctx = (duk_context *) thr; duk_small_uint_t depth; @@ -41232,8 +42196,8 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, duk_push_array(ctx); /* XXX: specify array size, as we know it */ arr_idx = 0; - /* compiler SyntaxErrors (and other errors) come first; blame the source - * code file/line primarily. + /* Compiler SyntaxErrors (and other errors) come first, and are + * blamed by default (not flagged "noblame"). */ if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { duk_push_hstring(ctx, thr->compile_ctx->h_filename); @@ -41245,7 +42209,7 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, arr_idx++; } - /* filename/line from C macros (__FILE__, __LINE__) are added as an + /* Filename/line from C macros (__FILE__, __LINE__) are added as an * entry with a special format: (string, number). The number contains * the line and flags. */ @@ -41258,7 +42222,9 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, /* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype * has write-protected array index named properties. This was seen as DoubleErrors * in e.g. some test262 test cases. Using duk_xdef_prop_index() is better but heavier. - * The best fix is to fill in the tracedata directly into the array part. + * The best fix is to fill in the tracedata directly into the array part. There are + * no side effect concerns if the array part is allocated directly and only INCREFs + * happen after that. */ /* [ ... error arr ] */ @@ -41329,34 +42295,22 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, } #endif /* DUK_USE_TRACEBACKS */ -#if defined(DUK_USE_AUGMENT_ERROR_CREATE) -DUK_LOCAL void duk__err_augment_builtin_throw(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) { - duk_context *ctx = (duk_context *) thr; -#ifdef DUK_USE_ASSERTIONS +/* + * Add .fileName and .lineNumber to an error on the stack top. + */ + +#if !defined(DUK_USE_TRACEBACKS) +DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) { + duk_context *ctx; +#if defined(DUK_USE_ASSERTIONS) duk_int_t entry_top; #endif -#ifdef DUK_USE_ASSERTIONS + ctx = (duk_context *) thr; +#if defined(DUK_USE_ASSERTIONS) entry_top = duk_get_top(ctx); #endif - DUK_ASSERT(obj != NULL); - DUK_UNREF(obj); /* unreferenced w/o tracebacks */ - DUK_UNREF(ctx); /* unreferenced w/ tracebacks */ - -#ifdef DUK_USE_TRACEBACKS - /* - * If tracebacks are enabled, the '_Tracedata' property is the only - * thing we need: 'fileName' and 'lineNumber' are virtual properties - * which use '_Tracedata'. - */ - - if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) { - DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it")); - } else { - duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline); - } -#else /* * If tracebacks are disabled, 'fileName' and 'lineNumber' are added * as plain own properties. Since Error.prototype has accessors of @@ -41366,33 +42320,49 @@ DUK_LOCAL void duk__err_augment_builtin_throw(duk_hthread *thr, duk_hthread *thr */ if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { - /* Compiler SyntaxError (or other error) gets the primary blame. */ - duk_push_hstring(ctx, thr->compile_ctx->h_filename); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); + /* Compiler SyntaxError (or other error) gets the primary blame. + * Currently no flag to prevent blaming. + */ duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); + duk_push_hstring(ctx, thr->compile_ctx->h_filename); } else if (c_filename && !noblame_fileline) { - /* XXX: file/line is disabled in minimal builds, so disable this too - * when appropriate. + /* C call site gets blamed next, unless flagged not to do so. + * XXX: file/line is disabled in minimal builds, so disable this + * too when appropriate. */ - duk_push_string(ctx, c_filename); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); duk_push_int(ctx, c_line); - duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); - } else if (thr_callstack->callstack_top > 0) { - duk_activation *act; - duk_hobject *func; + duk_push_string(ctx, c_filename); + } else { + /* Finally, blame the innermost callstack entry which has a + * .fileName property. + */ + duk_small_uint_t depth; + duk_int_t i, i_min; + duk_uint32_t ecma_line; - act = thr_callstack->callstack + thr_callstack->callstack_top - 1; - DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size); - func = DUK_ACT_GET_FUNC(act); - if (func) { + depth = DUK_USE_TRACEBACK_DEPTH; + i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0); + DUK_ASSERT(i_min >= 0); + + DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */ + for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) { + duk_activation *act; + duk_hobject *func; duk_uint32_t pc; - /* PC points to next instruction, find offending PC. Note that + act = thr_callstack->callstack + i; + DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size); + + func = DUK_ACT_GET_FUNC(act); + if (func == NULL) { + /* Lightfunc, not blamed now. */ + continue; + } + + /* PC points to next instruction, find offending PC, * PC == 0 for native code. */ - pc = duk_hthread_get_act_prev_pc(thr, act); + pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */ DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ act = NULL; /* invalidated by pushes, so get out of the way */ @@ -41402,31 +42372,126 @@ DUK_LOCAL void duk__err_augment_builtin_throw(duk_hthread *thr, duk_hthread *thr /* [ ... error func ] */ duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME); - duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); + if (!duk_is_string(ctx, -1)) { + duk_pop_2(ctx); + continue; + } + /* [ ... error func fileName ] */ + + ecma_line = 0; #if defined(DUK_USE_PC2LINE) if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) { - duk_uint32_t ecma_line; -#if 0 - duk_push_u32(ctx, pc); - duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PC, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAGS_NO_OVERWRITE); -#endif - ecma_line = duk_hobject_pc2line_query(ctx, -1, (duk_uint_fast32_t) pc); - if (ecma_line > 0) { - duk_push_u32(ctx, (duk_uint32_t) ecma_line); /* -> [ ... error func line ] */ - duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); - } + ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc); } else { /* Native function, no relevant lineNumber. */ } #endif /* DUK_USE_PC2LINE */ + duk_push_u32(ctx, ecma_line); - duk_pop(ctx); + /* [ ... error func fileName lineNumber ] */ + + duk_replace(ctx, -3); + + /* [ ... error lineNumber fileName ] */ + goto define_props; } + + /* No activation matches, use undefined for both .fileName and + * .lineNumber (matches what we do with a _Tracedata based + * no-match lookup. + */ + duk_push_undefined(ctx); + duk_push_undefined(ctx); } -#endif /* DUK_USE_TRACEBACKS */ -#ifdef DUK_USE_ASSERTIONS + define_props: + /* [ ... error lineNumber fileName ] */ +#if defined(DUK_USE_ASSERTIONS) + DUK_ASSERT(duk_get_top(ctx) == entry_top + 2); +#endif + duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE); +} +#endif /* !DUK_USE_TRACEBACKS */ + +/* + * Add line number to a compiler error. + */ + +DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) { + duk_context *ctx; + + /* Append a "(line NNN)" to the "message" property of any error + * thrown during compilation. Usually compilation errors are + * SyntaxErrors but they can also be out-of-memory errors and + * the like. + */ + + /* [ ... error ] */ + + ctx = (duk_context *) thr; + DUK_ASSERT(duk_is_object(ctx, -1)); + + if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) { + return; + } + + DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T", + (duk_tval *) duk_get_tval(ctx, -1))); + + if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) { + duk_push_sprintf(ctx, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line); + duk_concat(ctx, 2); + duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE); + } else { + duk_pop(ctx); + } + + DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T", + (duk_tval *) duk_get_tval(ctx, -1))); +} + +/* + * Augment an error being created using Duktape specific properties + * like _Tracedata or .fileName/.lineNumber. + */ + +#if defined(DUK_USE_AUGMENT_ERROR_CREATE) +DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) { + duk_context *ctx = (duk_context *) thr; +#if defined(DUK_USE_ASSERTIONS) + duk_int_t entry_top; +#endif + +#if defined(DUK_USE_ASSERTIONS) + entry_top = duk_get_top(ctx); +#endif + DUK_ASSERT(obj != NULL); + + DUK_UNREF(obj); /* unreferenced w/o tracebacks */ + DUK_UNREF(ctx); /* unreferenced w/o asserts */ + + duk__add_compiler_error_line(thr); + +#if defined(DUK_USE_TRACEBACKS) + /* If tracebacks are enabled, the '_Tracedata' property is the only + * thing we need: 'fileName' and 'lineNumber' are virtual properties + * which use '_Tracedata'. + */ + if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) { + DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it")); + } else { + duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline); + } +#else + /* Without tracebacks the concrete .fileName and .lineNumber need + * to be added directly. + */ + duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline); +#endif + +#if defined(DUK_USE_ASSERTIONS) DUK_ASSERT(duk_get_top(ctx) == entry_top); #endif } @@ -41487,7 +42552,7 @@ DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *th } if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) { DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment")); - duk__err_augment_builtin_throw(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj); + duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj); } else { DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment")); } @@ -41554,7 +42619,8 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) { * catcher. Protected calls or finally blocks aren't considered catching. */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) +#if defined(DUK_USE_DEBUGGER_SUPPORT) && \ + (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)) DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) { /* * XXX: As noted above, a protected API call won't be counted as a @@ -41578,7 +42644,7 @@ DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) { } return 0; } -#endif /* DUK_USE_DEBUGGER_SUPPORT */ +#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */ /* * Get prototype object for an integer error code. @@ -42231,7 +43297,7 @@ DUK_LOCAL void duk__free_allocated(duk_heap *heap) { } } -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) { duk_heaphdr *curr; duk_heaphdr *next; @@ -42247,7 +43313,7 @@ DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) { } #endif -#ifdef DUK_USE_MARK_AND_SWEEP +#if defined(DUK_USE_MARK_AND_SWEEP) DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) { duk_heaphdr *curr; duk_heaphdr *next; @@ -42271,16 +43337,17 @@ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { duk_hthread *thr; duk_heaphdr *curr; -#ifdef DUK_USE_DEBUG - duk_size_t count_obj = 0; -#endif + duk_uint_t round_no; + duk_size_t count_all; + duk_size_t count_finalized; + duk_size_t curr_limit; DUK_ASSERT(heap != NULL); DUK_ASSERT(heap->heap_thread != NULL); -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */ #endif -#ifdef DUK_USE_MARK_AND_SWEEP +#if defined(DUK_USE_MARK_AND_SWEEP) DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */ #endif @@ -42290,30 +43357,74 @@ DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { thr = heap->heap_thread; DUK_ASSERT(thr != NULL); - curr = heap->heap_allocated; - while (curr) { - if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) { - /* Only objects in heap_allocated may have finalizers. Check that - * the object itself has a _Finalizer property so that we don't - * execute finalizers for e.g. Proxy objects. - */ - DUK_ASSERT(thr != NULL); - DUK_ASSERT(curr != NULL); + /* Prevent mark-and-sweep for the pending finalizers, also prevents + * refzero handling from moving objects away from the heap_allocated + * list. + */ + DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); - if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); + curr_limit = 0; /* suppress warning, not used */ + for (round_no = 0; ; round_no++) { + curr = heap->heap_allocated; + count_all = 0; + count_finalized = 0; + while (curr) { + count_all++; + if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) { + /* Only objects in heap_allocated may have finalizers. Check that + * the object itself has a _Finalizer property (own or inherited) + * so that we don't execute finalizers for e.g. Proxy objects. + */ + DUK_ASSERT(thr != NULL); + DUK_ASSERT(curr != NULL); + + if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { + if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) { + DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */ + duk_hobject_run_finalizer(thr, (duk_hobject *) curr); + count_finalized++; + } + } } -#ifdef DUK_USE_DEBUG - count_obj++; -#endif + curr = DUK_HEAPHDR_GET_NEXT(heap, curr); + } + + /* Each round of finalizer execution may spawn new finalizable objects + * which is normal behavior for some applications. Allow multiple + * rounds of finalization, but use a shrinking limit based on the + * first round to detect the case where a runaway finalizer creates + * an unbounded amount of new finalizable objects. Finalizer rescue + * is not supported: the semantics are unclear because most of the + * objects being finalized here are already reachable. The finalizer + * is given a boolean to indicate that rescue is not possible. + * + * See discussion in: https://github.com/svaarala/duktape/pull/473 + */ + + if (round_no == 0) { + /* Cannot wrap: each object is at least 8 bytes so count is + * at most 1/8 of that. + */ + curr_limit = count_all * 2; + } else { + curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */ + } + DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld", + (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit)); + + if (count_finalized == 0) { + DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished")); + break; + } + if (count_finalized >= curr_limit) { + DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers")); + break; } - curr = DUK_HEAPHDR_GET_NEXT(heap, curr); } - /* Note: count includes all objects, not only those with an actual finalizer. */ -#ifdef DUK_USE_DEBUG - DUK_D(DUK_DPRINT("checked %ld objects for finalizers before freeing heap", (long) count_obj)); -#endif + DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); + DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); } DUK_INTERNAL void duk_heap_free(duk_heap *heap) { @@ -42327,6 +43438,9 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) { /* Detach a debugger if attached (can be called multiple times) * safely. */ + /* XXX: Add a flag to reject an attempt to re-attach? Otherwise + * the detached callback may immediately reattach. + */ duk_debug_do_detach(heap); #endif @@ -42334,18 +43448,30 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) { * objects, and regardless of whether or not mark-and-sweep is * enabled. This gives finalizers the chance to free any native * resources like file handles, allocations made outside Duktape, - * etc. + * etc. This is quite tricky to get right, so that all finalizer + * guarantees are honored. * * XXX: this perhaps requires an execution time limit. */ DUK_D(DUK_DPRINT("execute finalizers before freeing heap")); -#ifdef DUK_USE_MARK_AND_SWEEP - /* run mark-and-sweep a few times just in case (unreachable - * object finalizers run already here) - */ +#if defined(DUK_USE_MARK_AND_SWEEP) + /* Run mark-and-sweep a few times just in case (unreachable object + * finalizers run already here). The last round must rescue objects + * from the previous round without running any more finalizers. This + * ensures rescued objects get their FINALIZED flag cleared so that + * their finalizer is called once more in forced finalization to + * satisfy finalizer guarantees. However, we don't want to run any + * more finalizer because that'd required one more loop, and so on. + */ + DUK_D(DUK_DPRINT("forced gc #1 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); + DUK_D(DUK_DPRINT("forced gc #2 in heap destruction")); duk_heap_mark_and_sweep(heap, 0); + DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)")); + duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */ #endif + + DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */ duk__free_run_finalizers(heap); /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object @@ -42355,12 +43481,12 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) { DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap)); duk__free_allocated(heap); -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap)); duk__free_refzero_list(heap); #endif -#ifdef DUK_USE_MARK_AND_SWEEP +#if defined(DUK_USE_MARK_AND_SWEEP) DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap)); duk__free_markandsweep_finalize_list(heap); #endif @@ -42507,7 +43633,7 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { return 1; } -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) #define DUK__DUMPSZ(t) do { \ DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \ } while (0) @@ -42521,18 +43647,18 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \ (long) (a), (long) (b), \ (double) (a), (double) (b))); \ - } while(0) + } while (0) #define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \ DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \ (unsigned long) (a), (unsigned long) (b), \ (double) (a), (double) (b))); \ - } while(0) + } while (0) #define DUK__DUMPLM_SIGNED(t) do { \ DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \ - } while(0) + } while (0) #define DUK__DUMPLM_UNSIGNED(t) do { \ DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \ - } while(0) + } while (0) DUK_LOCAL void duk__dump_type_sizes(void) { DUK_D(DUK_DPRINT("sizeof()")); @@ -42694,19 +43820,27 @@ DUK_LOCAL void duk__dump_type_limits(void) { DUK_LOCAL void duk__dump_misc_options(void) { DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION)); DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE)); + DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING)); + DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING)); + DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING)); #if defined(DUK_USE_PACKED_TVAL) DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes")); #else DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no")); #endif +#if defined(DUK_USE_VARIADIC_MACROS) + DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes")); +#else + DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no")); +#endif #if defined(DUK_USE_INTEGER_LE) - DUK_D(DUK_DPRINT("Integer endianness: little")); + DUK_D(DUK_DPRINT("integer endianness: little")); #elif defined(DUK_USE_INTEGER_ME) - DUK_D(DUK_DPRINT("Integer endianness: mixed")); + DUK_D(DUK_DPRINT("integer endianness: mixed")); #elif defined(DUK_USE_INTEGER_BE) - DUK_D(DUK_DPRINT("Integer endianness: big")); + DUK_D(DUK_DPRINT("integer endianness: big")); #else - DUK_D(DUK_DPRINT("Integer endianness: ???")); + DUK_D(DUK_DPRINT("integer endianness: ???")); #endif #if defined(DUK_USE_DOUBLE_LE) DUK_D(DUK_DPRINT("IEEE double endianness: little")); @@ -42737,7 +43871,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, * Debug dump type sizes */ -#ifdef DUK_USE_DEBUG +#if defined(DUK_USE_DEBUG) duk__dump_misc_options(); duk__dump_type_sizes(); duk__dump_type_limits(); @@ -42746,7 +43880,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, /* * If selftests enabled, run them as early as possible */ -#ifdef DUK_USE_SELF_TESTS +#if defined(DUK_USE_SELF_TESTS) DUK_D(DUK_DPRINT("running self tests")); duk_selftest_run_tests(); DUK_D(DUK_DPRINT("self tests passed")); @@ -42756,7 +43890,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, * Computed values (e.g. INFINITY) */ -#ifdef DUK_USE_COMPUTED_NAN +#if defined(DUK_USE_COMPUTED_NAN) do { /* Workaround for some exotic platforms where NAN is missing * and the expression (0.0 / 0.0) does NOT result in a NaN. @@ -42772,7 +43906,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, } while (0); #endif -#ifdef DUK_USE_COMPUTED_INFINITY +#if defined(DUK_USE_COMPUTED_INFINITY) do { /* Similar workaround for INFINITY. */ volatile double dbl1 = 1.0; @@ -42799,14 +43933,14 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, DUK_MEMZERO(res, sizeof(*res)); /* explicit NULL inits */ -#ifdef DUK_USE_EXPLICIT_NULL_INIT +#if defined(DUK_USE_EXPLICIT_NULL_INIT) res->heap_udata = NULL; res->heap_allocated = NULL; -#ifdef DUK_USE_REFERENCE_COUNTING +#if defined(DUK_USE_REFERENCE_COUNTING) res->refzero_list = NULL; res->refzero_list_tail = NULL; #endif -#ifdef DUK_USE_MARK_AND_SWEEP +#if defined(DUK_USE_MARK_AND_SWEEP) res->finalize_list = NULL; #endif res->heap_thread = NULL; @@ -42869,8 +44003,11 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, */ res->hash_seed = (duk_uint32_t) (duk_intptr_t) res; res->rnd_state = (duk_uint32_t) (duk_intptr_t) res; +#if !defined(DUK_USE_STRHASH_DENSE) + res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */ +#endif -#ifdef DUK_USE_EXPLICIT_NULL_INIT +#if defined(DUK_USE_EXPLICIT_NULL_INIT) res->lj.jmpbuf_ptr = NULL; #endif DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ @@ -42888,7 +44025,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, #if defined(DUK_USE_STRTAB_CHAIN) DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE); -#ifdef DUK_USE_EXPLICIT_NULL_INIT +#if defined(DUK_USE_EXPLICIT_NULL_INIT) { duk_small_uint_t i; for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { @@ -42919,7 +44056,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, } #endif /* DUK_USE_HEAPPTR16 */ res->st_size = DUK_STRTAB_INITIAL_SIZE; -#ifdef DUK_USE_EXPLICIT_NULL_INIT +#if defined(DUK_USE_EXPLICIT_NULL_INIT) { duk_small_uint_t i; DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE); @@ -42944,7 +44081,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, * Init stringcache */ -#ifdef DUK_USE_EXPLICIT_NULL_INIT +#if defined(DUK_USE_EXPLICIT_NULL_INIT) { duk_small_uint_t i; for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { @@ -43014,11 +44151,23 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, #line 1 "duk_heap_hashstring.c" /* * String hash computation (interning). + * + * String hashing is performance critical because a string hash is computed + * for all new strings which are candidates to be added to the string table. + * However, strings actually added to the string table go through a codepoint + * length calculation which dominates performance because it goes through + * every byte of the input string (but only for strings added). + * + * The string hash algorithm should be fast, but on the other hand provide + * good enough hashes to ensure both string table and object property table + * hash tables work reasonably well (i.e., there aren't too many collisions + * with real world inputs). Unless the hash is cryptographic, it's always + * possible to craft inputs with maximal hash collisions. */ /* include removed: duk_internal.h */ -/* constants for duk_hashstring() */ +#if defined(DUK_USE_STRHASH_DENSE) #define DUK__STRHASH_SHORTSTRING 4096L #define DUK__STRHASH_MEDIUMSTRING (256L * 1024L) #define DUK__STRHASH_BLOCKSIZE 256L @@ -43026,25 +44175,21 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { duk_uint32_t hash; - /* - * Sampling long strings by byte skipping (like Lua does) is potentially - * a cache problem. Here we do 'block skipping' instead for long strings: - * hash an initial part, and then sample the rest of the string with - * reasonably sized chunks. - * - * Skip should depend on length and bound the total time to roughly - * logarithmic. + /* Use Murmurhash2 directly for short strings, and use "block skipping" + * for long strings: hash an initial part and then sample the rest of + * the string with reasonably sized chunks. An initial offset for the + * sampling is computed based on a hash of the initial part of the string; + * this is done to (usually) avoid the case where all long strings have + * certain offset ranges which are never sampled. * - * With current values: + * Skip should depend on length and bound the total time to roughly + * logarithmic. With current values: * - * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing - * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing + * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing + * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing * - * After an initial part has been hashed, an offset is applied before - * starting the sampling. The initial offset is computed from the - * hash of the initial part of the string. The idea is to avoid the - * case that all long strings have certain offset ranges that are never - * sampled. + * XXX: It would be better to compute the skip offset more "smoothly" + * instead of having a few boundary values. */ /* note: mixing len into seed improves hashing when skipping */ @@ -43082,6 +44227,44 @@ DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t #endif return hash; } + +#undef DUK__STRHASH_SHORTSTRING +#undef DUK__STRHASH_MEDIUMSTRING +#undef DUK__STRHASH_BLOCKSIZE +#else /* DUK_USE_STRHASH_DENSE */ +DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { + duk_uint32_t hash; + duk_size_t step; + duk_size_t off; + + /* Slightly modified "Bernstein hash" from: + * + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx + * + * Modifications: string skipping and reverse direction similar to + * Lua 5.1.5, and different hash initializer. + * + * The reverse direction ensures last byte it always included in the + * hash which is a good default as changing parts of the string are + * more often in the suffix than in the prefix. + */ + + hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */ + step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1; + for (off = len; off >= step; off -= step) { + DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */ + hash = (hash * 33) + str[off - 1]; + } + +#if defined(DUK_USE_STRHASH16) + /* Truncate to 16 bits here, so that a computed hash can be compared + * against a hash stored in a 16-bit field. + */ + hash &= 0x0000ffffUL; +#endif + return hash; +} +#endif /* DUK_USE_STRHASH_DENSE */ #line 1 "duk_heap_markandsweep.c" /* * Mark-and-sweep garbage collection. @@ -43940,7 +45123,7 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_ * Run (object) finalizers in the "to be finalized" work list. */ -DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap) { +DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) { duk_heaphdr *curr; duk_heaphdr *next; #ifdef DUK_USE_DEBUG @@ -43963,13 +45146,22 @@ DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap) { DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - /* run the finalizer */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */ - - /* mark FINALIZED, for next mark-and-sweep (will collect unless has become reachable; - * prevent running finalizer again if reachable) - */ - DUK_HEAPHDR_SET_FINALIZED(curr); + if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) { + /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED. + * Next mark-and-sweep will collect the object unless it has + * become reachable (i.e. rescued). FINALIZED prevents the + * finalizer from being executed again before that. + */ + duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */ + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); + } else { + /* Used during heap destruction: don't actually run finalizers + * because we're heading into forced finalization. Instead, + * queue finalizable objects back to the heap_allocated list. + */ + DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing")); + DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); + } /* queue back to heap_allocated */ next = DUK_HEAPHDR_GET_NEXT(heap, curr); @@ -44406,7 +45598,7 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t if (flags & DUK_MS_FLAG_NO_FINALIZERS) { DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set")); } else { - duk__run_object_finalizers(heap); + duk__run_object_finalizers(heap, flags); } /* @@ -45210,10 +46402,9 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) { * objects and must be safe (not throw any errors, ever). */ - /* XXX: If object has FINALIZED, it was finalized by mark-and-sweep on - * its previous run. Any point in running finalizer again here? If - * finalization semantics is changed so that finalizer is only run once, - * checking for FINALIZED would happen here. + /* An object may have FINALIZED here if it was finalized by mark-and-sweep + * on a previous run and refcount then decreased to zero. We won't run the + * finalizer again here. */ /* A finalizer is looked up from the object and up its prototype chain @@ -45226,6 +46417,7 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) { DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ duk_hobject_run_finalizer(thr, obj); /* must never longjmp */ + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */ DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ @@ -45266,6 +46458,9 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) { if (rescued) { /* yes -> move back to heap allocated */ DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1)); + DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1)); + DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); + DUK_HEAPHDR_CLEAR_FINALIZED(h1); DUK_HEAPHDR_SET_PREV(heap, h1, NULL); DUK_HEAPHDR_SET_NEXT(heap, h1, heap->heap_allocated); heap->heap_allocated = h1; @@ -45319,22 +46514,25 @@ DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { heap = thr->heap; DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h)); -#ifdef DUK_USE_MARK_AND_SWEEP /* * If mark-and-sweep is running, don't process 'refzero' situations at all. * They may happen because mark-and-sweep needs to finalize refcounts for * each object it sweeps. Otherwise the target objects of swept objects * would have incorrect refcounts. * + * This check must be enabled also when mark-and-sweep support has been + * disabled: the flag is also used in heap destruction when running + * finalizers for remaining objects, and the flag prevents objects from + * being moved around in heap linked lists. + * * Note: mark-and-sweep could use a separate decref handler to avoid coming * here at all. However, mark-and-sweep may also call finalizers, which * can do arbitrary operations and would use this decref variant anyway. */ - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { + if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))) { DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h)); return; } -#endif switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) { case DUK_HTYPE_STRING: @@ -45531,9 +46729,13 @@ DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h /* * String scanning helpers + * + * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are + * considered to contribute a character. This must match how string + * character length is computed. */ -DUK_LOCAL duk_uint8_t *duk__scan_forwards(duk_uint8_t *p, duk_uint8_t *q, duk_uint_fast32_t n) { +DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) { while (n > 0) { for (;;) { p++; @@ -45549,7 +46751,7 @@ DUK_LOCAL duk_uint8_t *duk__scan_forwards(duk_uint8_t *p, duk_uint8_t *q, duk_ui return p; } -DUK_LOCAL duk_uint8_t *duk__scan_backwards(duk_uint8_t *p, duk_uint8_t *q, duk_uint_fast32_t n) { +DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) { while (n > 0) { for (;;) { p--; @@ -45584,9 +46786,9 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t duk_small_int_t i; duk_bool_t use_cache; duk_uint_fast32_t dist_start, dist_end, dist_sce; - duk_uint8_t *p_start; - duk_uint8_t *p_end; - duk_uint8_t *p_found; + const duk_uint8_t *p_start; + const duk_uint8_t *p_end; + const duk_uint8_t *p_found; if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) { goto error; @@ -45653,8 +46855,8 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset; dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */ - p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h); - p_end = (duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h)); + p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); + p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h)); p_found = NULL; if (sce) { @@ -45765,7 +46967,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t tmp = *sce; DUK_MEMMOVE((void *) (&heap->strcache[1]), - (void *) (&heap->strcache[0]), + (const void *) (&heap->strcache[0]), (size_t) (((char *) sce) - ((char *) &heap->strcache[0]))); heap->strcache[0] = tmp; @@ -46040,7 +47242,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16); DUK_ASSERT(h != NULL); if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(h), blen) == 0) { + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { return h; } } @@ -46053,7 +47255,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]); DUK_ASSERT(h != NULL); if (DUK_HSTRING_GET_BYTELEN(h) == blen && - DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(h), blen) == 0) { + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { return h; } } @@ -46078,7 +47280,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk if (e->listlen == 0) { if (e->u.str != NULL && DUK_HSTRING_GET_BYTELEN(e->u.str) == blen && - DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(e->u.str), blen) == 0) { + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) { return e->u.str; } } else { @@ -46087,7 +47289,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk for (i = 0, n = e->listlen; i < n; i++) { if (lst[i] != NULL && DUK_HSTRING_GET_BYTELEN(lst[i]) == blen && - DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(lst[i]), blen) == 0) { + DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) { return lst[i]; } } @@ -46339,7 +47541,7 @@ DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstri return NULL; } if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) { - if (DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(e), blen) == 0) { + if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) { DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)", (long) i, (long) step, (long) size)); return e; @@ -47241,7 +48443,7 @@ DUK_LOCAL void duk__sort_array_indices(duk_hthread *thr, duk_hobject *h_obj) { (long) (p_curr - p_insert), (void *) h_curr)); DUK_MEMMOVE((void *) (p_insert + 1), - (void *) p_insert, + (const void *) p_insert, (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *))); *p_insert = h_curr; /* keep val_highest */ @@ -47747,7 +48949,10 @@ DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_sma /* include removed: duk_internal.h */ DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) { + duk_hthread *thr; + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; DUK_DDD(DUK_DDDPRINT("protected finalization helper running")); @@ -47765,9 +48970,10 @@ DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) { DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable")); return 0; } - duk_dup(ctx, -2); /* -> [... obj finalizer obj] */ + duk_dup(ctx, -2); + duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer")); - duk_call(ctx, 1); /* -> [... obj retval] */ + duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ DUK_DDD(DUK_DDDPRINT("finalizer finished successfully")); return 0; @@ -47800,6 +49006,20 @@ DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) * may trigger an error (getter may throw one, for instance). */ + if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) { + DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj)); + return; + } + DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */ + if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) { + /* This shouldn't happen; call sites should avoid looking up + * _Finalizer "through" a Proxy, but ignore if we come here + * with a Proxy to avoid finalizer re-entry. + */ + DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call")); + return; + } + /* XXX: use a NULL error handler for the finalizer call? */ DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper")); @@ -49469,6 +50689,11 @@ DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, DUK_ASSERT(heap != NULL); DUK_ASSERT(obj != NULL); + /* This is not strictly necessary, but avoids compiler warnings; e.g. + * gcc won't reliably detect that no uninitialized data is read below. + */ + DUK_MEMZERO((void *) &tv, sizeof(duk_tval)); + if (duk_hobject_get_internal_value(heap, obj, &tv)) { duk_hstring *h; DUK_ASSERT(DUK_TVAL_IS_STRING(&tv)); @@ -50367,7 +51592,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, case DUK_TAG_NULL: { /* Note: unconditional throw */ DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject")); +#if defined(DUK_USE_PARANOID_ERRORS) DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE); +#else + DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s", + duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj)); +#endif return 0; } @@ -51402,7 +52632,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, /* Note: unconditional throw */ DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)", (duk_tval *) tv_obj)); +#if defined(DUK_USE_PARANOID_ERRORS) DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE); +#else + DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s", + duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj)); +#endif return 0; } @@ -52159,7 +53394,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, fail_base_primitive: DUK_DDD(DUK_DDDPRINT("result: error, base primitive")); if (throw_flag) { +#if defined(DUK_USE_PARANOID_ERRORS) DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE); +#else + DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s", + duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj)); +#endif } duk_pop(ctx); /* remove key */ return 0; @@ -52521,7 +53761,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, fail_invalid_base_uncond: /* Note: unconditional throw */ DUK_ASSERT(duk_get_top(ctx) == entry_top); +#if defined(DUK_USE_PARANOID_ERRORS) DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_BASE); +#else + DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s", + duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj)); +#endif return 0; fail_proxy_rejected: @@ -54041,7 +55286,8 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk p_end = p_start + DUK_HSTRING_GET_BYTELEN(h); p = p_start + boff; DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p", - (void *) p_start, (void *) p_end, (void *) p)); + (const void *) p_start, (const void *) p_end, + (const void *) p)); /* This may throw an error though not for valid E5 strings. */ cp = duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); @@ -54476,9 +55722,6 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { duk_c_function c_func_getter; duk_c_function c_func_setter; - /* XXX: this is a bit awkward because there is no exposed helper - * in the API style, only this internal helper. - */ DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, stridx=%ld, getteridx=%ld, setteridx=%ld, flags=0x%04lx", (long) i, (long) stridx, (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags)); @@ -54487,7 +55730,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */ duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */ - /* XXX: magic for getter/setter? */ + /* XXX: magic for getter/setter? use duk_def_prop()? */ prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */ duk_hobject_define_accessor_internal(thr, @@ -54682,9 +55925,6 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { "m" #else "?" -#endif -#if defined(DUK_USE_BYTEORDER_FORCED) - "f" #endif " " /* Packed or unpacked tval */ @@ -56124,7 +57364,12 @@ duk_hobject *duk__nonbound_func_lookup(duk_context *ctx, return func; not_callable_error: + DUK_ASSERT(tv_func != NULL); +#if defined(DUK_USE_PARANOID_ERRORS) DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE); +#else + DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func)); +#endif DUK_UNREACHABLE(); return NULL; /* never executed */ } @@ -56245,7 +57490,7 @@ duk_int_t duk_handle_call(duk_hthread *thr, duk_instr_t **entry_ptr_curr_pc; volatile duk_bool_t need_setjmp; duk_jmpbuf * volatile old_jmpbuf_ptr = NULL; /* ptr is volatile (not the target) */ - volatile duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */ + duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */ duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */ duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */ duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */ @@ -56341,7 +57586,7 @@ duk_int_t duk_handle_call(duk_hthread *thr, * call the fatal error handler. */ - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); } /* @@ -56806,7 +58051,7 @@ duk_int_t duk_handle_call(duk_hthread *thr, duk_error_throw_from_negative_rc(thr, rc); DUK_UNREACHABLE(); } else if (rc > 1) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, "c function returned invalid rc"); + DUK_ERROR_API(thr, "c function returned invalid rc"); } DUK_ASSERT(rc == 0 || rc == 1); @@ -57201,7 +58446,7 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr, * call the fatal error handler. */ - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); } /* setjmp catchpoint setup */ @@ -57353,7 +58598,7 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr, DUK_ASSERT(rc >= 0); if (duk_get_top(ctx) < rc) { - DUK_ERROR(thr, DUK_ERR_API_ERROR, "not enough stack values for safe_call rc"); + DUK_ERROR_API(thr, "not enough stack values for safe_call rc"); } duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); @@ -57536,7 +58781,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, if (idx_func < 0 || idx_args < 0) { /* XXX: assert? compiler is responsible for this never happening */ - DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS); + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); } /* @@ -58093,7 +59338,7 @@ DUK_LOCAL_DECL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *co /* statement parsing */ DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname); -DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); +DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags); DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); @@ -58185,11 +59430,11 @@ DUK_LOCAL const duk_uint8_t duk__token_lbp[] = { DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */ + DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */ - DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */ DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */ @@ -61681,9 +62926,17 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i case DUK_TOK_PERIOD: { /* Property access expressions are critical for correct LHS ordering, * see comments in duk__expr()! + * + * A conservative approach would be to use duk__ivalue_totempconst() + * for 'left'. However, allowing a reg-bound variable seems safe here + * and is nice because "foo.bar" is a common expression. If the ivalue + * is used in an expression a GETPROP will occur before any changes to + * the base value can occur. If the ivalue is used as an assignment + * LHS, the assignment code will ensure the base value is safe from + * RHS mutation. */ - /* XXX: this now coerces an identifier into a GETVAR to a temp, which + /* XXX: This now coerces an identifier into a GETVAR to a temp, which * causes an extra LDREG in call setup. It's sufficient to coerce to a * unary ivalue? */ @@ -61714,13 +62967,22 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i /* XXX: optimize temp reg use */ /* XXX: similar coercion issue as in DUK_TOK_PERIOD */ - /* XXX: coerce to regs? it might be better for enumeration use, where the * same PROP ivalue is used multiple times. Or perhaps coerce PROP further * there? */ + /* XXX: for simple cases like x['y'] an unnecessary LDREG is + * emitted for the base value; could avoid it if we knew that + * the key expression is safe (e.g. just a single literal). + */ - duk__ivalue_toplain(comp_ctx, left); + /* The 'left' value must not be a register bound variable + * because it may be mutated during the rest of the expression + * and E5.1 Section 11.2.1 specifies the order of evaluation + * so that the base value is evaluated first. + * See: test-bug-nested-prop-mutate.js. + */ + duk__ivalue_totempconst(comp_ctx, left); duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */ duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET); @@ -62558,8 +63820,9 @@ DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) { */ #define DUK__EXPR_RBP_MASK 0xff -#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) -#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) +#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */ +#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */ +#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */ /* main expression parser function */ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { @@ -62833,6 +64096,11 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, (duk_regconst_t) reg_val, rc_varname); } + } else { + if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) { + /* Used for minimal 'const': initializer required. */ + goto syntax_error; + } } duk_pop(ctx); /* pop varname */ @@ -62846,7 +64114,7 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_INVALID_VAR_DECLARATION); } -DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { +DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) { duk_reg_t reg_varbind; duk_regconst_t rc_varname; @@ -62854,7 +64122,7 @@ DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) for (;;) { /* rc_varname and reg_varbind are ignored here */ - duk__parse_var_decl(comp_ctx, res, 0, ®_varbind, &rc_varname); + duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, ®_varbind, &rc_varname); if (comp_ctx->curr_token.t != DUK_TOK_COMMA) { break; @@ -64135,9 +65403,15 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_ stmt_flags = 0; break; } + case DUK_TOK_CONST: { + DUK_DDD(DUK_DDDPRINT("constant declaration statement")); + duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/); + stmt_flags = DUK__HAS_TERM; + break; + } case DUK_TOK_VAR: { DUK_DDD(DUK_DDDPRINT("variable declaration statement")); - duk__parse_var_stmt(comp_ctx, res); + duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/); stmt_flags = DUK__HAS_TERM; break; } @@ -65644,37 +66918,9 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer prev_ctx = thr->compile_ctx; thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */ safe_rc = duk_safe_call(ctx, duk__js_compile_raw, 2 /*nargs*/, 1 /*nret*/); - thr->compile_ctx = prev_ctx; + thr->compile_ctx = prev_ctx; /* must restore reliably before returning */ if (safe_rc != DUK_EXEC_SUCCESS) { - /* Append a "(line NNN)" to the "message" property of any - * error thrown during compilation. Usually compilation - * errors are SyntaxErrors but they can also be out-of-memory - * errors and the like. - * - * Source file/line are added to tracedata directly by - * duk_error_augment.c based on thr->compile_ctx. - */ - - /* [ ... error ] */ - - DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T", - (duk_tval *) duk_get_tval(ctx, -1))); - if (duk_is_object(ctx, -1)) { - /* XXX: Now that fileName and lineNumber are set, this is - * unnecessary. Remove in Duktape 1.3.0? - */ - - if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) { - duk_push_sprintf(ctx, " (line %ld)", (long) comp_stk.comp_ctx_alloc.curr_token.start_line); - duk_concat(ctx, 2); - duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE); - } else { - duk_pop(ctx); - } - } - DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T", - (duk_tval *) duk_get_tval(ctx, -1))); duk_throw(ctx); } @@ -70732,7 +71978,7 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d DUK_ASSERT(len_x == len_y); DUK_ASSERT(len_x == 0 || buf_x != NULL); DUK_ASSERT(len_y == 0 || buf_y != NULL); - return (DUK_MEMCMP(buf_x, buf_y, len_x) == 0) ? 1 : 0; + return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0; } } case DUK_TAG_LIGHTFUNC: { @@ -70811,20 +72057,20 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y); duk_size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x); duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y); - void *buf_x; - void *buf_y; + const void *buf_x; + const void *buf_y; if (len_x != len_y) { return 0; } - buf_x = (void *) DUK_HSTRING_GET_DATA(h_x); - buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y); + buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x); + buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y); /* if len_x == len_y == 0, buf_x and/or buf_y may * be NULL, but that's OK. */ DUK_ASSERT(len_x == len_y); DUK_ASSERT(len_x == 0 || buf_x != NULL); DUK_ASSERT(len_y == 0 || buf_y != NULL); - return (DUK_MEMCMP(buf_x, buf_y, len_x) == 0) ? 1 : 0; + return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0; } /* Boolean/any -> coerce boolean to number and try again. If boolean is @@ -70887,19 +72133,12 @@ DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const prefix_len = (len1 <= len2 ? len1 : len2); - /* XXX: this special case can now be removed with DUK_MEMCMP */ - /* memcmp() should return zero (equal) for zero length, but avoid - * it because there are some platform specific bugs. Don't use - * strncmp() because it stops comparing at a NUL. + /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length + * inputs so no zero length check is needed. */ - - if (prefix_len == 0) { - rc = 0; - } else { - rc = DUK_MEMCMP((const char *) buf1, - (const char *) buf2, - prefix_len); - } + rc = DUK_MEMCMP((const void *) buf1, + (const void *) buf2, + (size_t) prefix_len); if (rc < 0) { return -1; @@ -73781,7 +75020,7 @@ DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes; DUK_MEMMOVE((void *) lex_ctx->window, (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes), - (duk_size_t) keep_bytes); + (size_t) keep_bytes); cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes); cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE; @@ -75496,7 +76735,7 @@ DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) { if (n == 0) { return; } - DUK_MEMCPY((void *) x->v, (void *) y->v, (size_t) (sizeof(duk_uint32_t) * n)); + DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * n)); } DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) { @@ -76058,7 +77297,7 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x } len = (duk_size_t) ((buf + 32) - p); - DUK_MEMMOVE((void *) buf, (void *) p, (size_t) len); + DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len); return len; } @@ -76527,7 +77766,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify if (p == &nc_ctx->digits[0]) { DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling")); DUK_MEMMOVE((void *) (&nc_ctx->digits[1]), - (void *) (&nc_ctx->digits[0]), + (const void *) (&nc_ctx->digits[0]), (size_t) (sizeof(char) * nc_ctx->count)); nc_ctx->digits[0] = 1; /* don't increase 'count' */ nc_ctx->k++; /* position of highest digit changed */ @@ -77298,7 +78537,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, " "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld", - (void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch, + (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch, (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac, (long) dig_expt, (long) dig_lzero, (long) dig_prec)); DUK__BI_PRINT("f", &nc_ctx->f); @@ -79420,9 +80659,9 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_ DUK_MEMZERO(&re_ctx, sizeof(re_ctx)); re_ctx.thr = thr; - re_ctx.input = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); + re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input); - re_ctx.bytecode = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode); + re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode); re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode); re_ctx.saved = NULL; re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT; @@ -79519,8 +80758,8 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_ DUK_ASSERT(re_ctx.recursion_depth == 0); DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]", - (long) char_offset, (void *) sp, (void *) re_ctx.input, - (void *) re_ctx.input_end)); + (long) char_offset, (const void *) sp, + (const void *) re_ctx.input, (const void *) re_ctx.input_end)); /* * Note: @@ -79627,7 +80866,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_ duk_hstring *h_saved; duk_push_lstring(ctx, - (char *) re_ctx.saved[i], + (const char *) re_ctx.saved[i], (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i])); h_saved = duk_get_hstring(ctx, -1); DUK_ASSERT(h_saved != NULL); @@ -79719,15 +80958,15 @@ DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) { /* include removed: duk_internal.h */ -#ifdef DUK_USE_COMPUTED_NAN +#if defined(DUK_USE_COMPUTED_NAN) DUK_INTERNAL double duk_computed_nan; #endif -#ifdef DUK_USE_COMPUTED_INFINITY +#if defined(DUK_USE_COMPUTED_INFINITY) DUK_INTERNAL double duk_computed_infinity; #endif -#ifdef DUK_USE_REPL_FPCLASSIFY +#if defined(DUK_USE_REPL_FPCLASSIFY) DUK_INTERNAL int duk_repl_fpclassify(double x) { duk_double_union u; duk_uint_fast16_t expt; @@ -79759,7 +80998,7 @@ DUK_INTERNAL int duk_repl_fpclassify(double x) { } #endif -#ifdef DUK_USE_REPL_SIGNBIT +#if defined(DUK_USE_REPL_SIGNBIT) DUK_INTERNAL int duk_repl_signbit(double x) { duk_double_union u; u.d = x; @@ -79767,7 +81006,7 @@ DUK_INTERNAL int duk_repl_signbit(double x) { } #endif -#ifdef DUK_USE_REPL_ISFINITE +#if defined(DUK_USE_REPL_ISFINITE) DUK_INTERNAL int duk_repl_isfinite(double x) { int c = DUK_FPCLASSIFY(x); if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { @@ -79778,14 +81017,14 @@ DUK_INTERNAL int duk_repl_isfinite(double x) { } #endif -#ifdef DUK_USE_REPL_ISNAN +#if defined(DUK_USE_REPL_ISNAN) DUK_INTERNAL int duk_repl_isnan(double x) { int c = DUK_FPCLASSIFY(x); return (c == DUK_FP_NAN); } #endif -#ifdef DUK_USE_REPL_ISINF +#if defined(DUK_USE_REPL_ISINF) DUK_INTERNAL int duk_repl_isinf(double x) { int c = DUK_FPCLASSIFY(x); return (c == DUK_FP_INFINITE); @@ -79811,13 +81050,13 @@ typedef union { } duk__test_double_union; #define DUK__DBLUNION_CMP_TRUE(a,b) do { \ - if (DUK_MEMCMP((void *) (a), (void *) (b), sizeof(duk__test_double_union)) != 0) { \ + if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \ DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \ } \ } while (0) #define DUK__DBLUNION_CMP_FALSE(a,b) do { \ - if (DUK_MEMCMP((void *) (a), (void *) (b), sizeof(duk__test_double_union)) == 0) { \ + if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \ DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \ } \ } while (0) @@ -79877,7 +81116,11 @@ DUK_LOCAL void duk__selftest_packed_tval(void) { DUK_LOCAL void duk__selftest_twos_complement(void) { volatile int test; test = -1; - if (((duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) { + + /* Note that byte order doesn't affect this test: all bytes in + * 'test' will be 0xFF for two's complement. + */ + if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) { DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic"); } } @@ -79998,15 +81241,12 @@ DUK_LOCAL void duk__selftest_double_aliasing(void) { * It's not an issue because the failure should only affect packed * duk_tval representation, which is not used with Emscripten. */ -#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST) -#if defined(DUK_USE_PACKED_TVAL) -#error inconsistent defines: skipping double aliasing selftest when using packed duk_tval -#endif +#if !defined(DUK_USE_PACKED_TVAL) + DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed")); return; #endif - /* Test signaling NaN and alias assignment in all - * endianness combinations. + /* Test signaling NaN and alias assignment in all endianness combinations. */ /* little endian */ @@ -80033,7 +81273,7 @@ DUK_LOCAL void duk__selftest_double_aliasing(void) { */ DUK_LOCAL void duk__selftest_double_zero_sign(void) { - volatile duk__test_double_union a, b; + duk__test_double_union a, b; a.d = 0.0; b.d = -a.d; @@ -80587,7 +81827,7 @@ const duk_uint8_t duk_unicode_caseconv_lc[616] = { 141,2,101,2,2,97,0,52,129,131,128, }; -/* FIXME: CONDITIONAL */ +#if defined(DUK_USE_REGEXP_CANON_WORKAROUND) /* * Automatically generated by extract_caseconv.py, do not edit! */ @@ -85876,6 +87116,7 @@ const duk_uint16_t duk_unicode_re_canon_lookup[65536] = { 65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533, 65534,65535, }; +#endif #line 1 "duk_util_bitdecoder.c" /* * Bitstream decoder. @@ -86105,7 +87346,7 @@ DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw p_base = bw->p_base; DUK_MEMCPY((void *) bw->p, (const void *) (p_base + src_off), - (duk_size_t) len); + (size_t) len); bw->p += len; } @@ -86138,10 +87379,10 @@ DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *b DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ DUK_MEMMOVE((void *) (p_base + dst_off + len), (const void *) (p_base + dst_off), - (duk_size_t) move_sz); + (size_t) move_sz); DUK_MEMCPY((void *) (p_base + dst_off), (const void *) buf, - (duk_size_t) len); + (size_t) len); bw->p += len; } @@ -86186,10 +87427,10 @@ DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ DUK_MEMMOVE((void *) (p_base + dst_off + len), (const void *) (p_base + dst_off), - (duk_size_t) move_sz); + (size_t) move_sz); DUK_MEMCPY((void *) (p_base + dst_off), (const void *) (p_base + src_off), - (duk_size_t) len); + (size_t) len); bw->p += len; } @@ -86223,7 +87464,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter move_sz = buf_sz - off; p_dst = p_base + off + len; p_src = p_base + off; - DUK_MEMMOVE((void *) p_dst, (const void *) p_src, move_sz); + DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz); return p_src; /* point to start of 'reserved area' */ } @@ -86257,7 +87498,7 @@ DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b move_sz = (duk_size_t) (bw->p - p_src); DUK_MEMMOVE((void *) p_dst, (const void *) p_src, - move_sz); + (size_t) move_sz); bw->p -= len; } @@ -86278,7 +87519,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) duk_uint16_t x; } u; - DUK_MEMCPY((void *) u.b, (const void *) (*p), 2); + DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2); u.x = DUK_NTOH16(u.x); *p += 2; return u.x; @@ -86290,7 +87531,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) duk_uint32_t x; } u; - DUK_MEMCPY((void *) u.b, (const void *) (*p), 4); + DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4); u.x = DUK_NTOH32(u.x); *p += 4; return u.x; @@ -86303,10 +87544,10 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t * duk_uint32_t x; } u; - DUK_MEMCPY((void *) u.b, (const void *) (*p), 4); + DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4); u.x = DUK_NTOH32(u.x); du.ui[DUK_DBL_IDX_UI0] = u.x; - DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), 4); + DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4); u.x = DUK_NTOH32(u.x); du.ui[DUK_DBL_IDX_UI1] = u.x; *p += 8; @@ -86321,7 +87562,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_ui } u; u.x = DUK_HTON16(val); - DUK_MEMCPY((void *) (*p), (const void *) u.b, 2); + DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2); *p += 2; } @@ -86332,7 +87573,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_ui } u; u.x = DUK_HTON32(val); - DUK_MEMCPY((void *) (*p), (const void *) u.b, 4); + DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4); *p += 4; } @@ -86346,10 +87587,10 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk du.d = val; u.x = du.ui[DUK_DBL_IDX_UI0]; u.x = DUK_HTON32(u.x); - DUK_MEMCPY((void *) (*p), (const void *) u.b, 4); + DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4); u.x = du.ui[DUK_DBL_IDX_UI1]; u.x = DUK_HTON32(u.x); - DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, 4); + DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4); *p += 8; } #line 1 "duk_util_hashbytes.c" @@ -86364,6 +87605,7 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk /* include removed: duk_internal.h */ +#if defined(DUK_USE_STRHASH_DENSE) /* 'magic' constants for Murmurhash2 */ #define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL) #define DUK__MAGIC_R 24 @@ -86378,7 +87620,7 @@ DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t * OK as long as it is consistent for a build. */ #ifdef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS - duk_uint32_t k = *((duk_uint32_t *) (void *) data); + duk_uint32_t k = *((const duk_uint32_t *) (const void *) data); #else duk_uint32_t k = ((duk_uint32_t) data[0]) | (((duk_uint32_t) data[1]) << 8) | @@ -86408,6 +87650,7 @@ DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t return h; } +#endif /* DUK_USE_STRHASH_DENSE */ #line 1 "duk_util_tinyrandom.c" /* * A tiny random number generator. @@ -86472,4 +87715,3 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) { return t; } -#endif diff --git a/javascript/duktape/duktape.h b/javascript/duktape/duktape.h index 6fba18d8b..d672edeba 100644 --- a/javascript/duktape/duktape.h +++ b/javascript/duktape/duktape.h @@ -5,8 +5,8 @@ * include guard. Other parts of the header are Duktape * internal and related to platform/compiler/feature detection. * - * Git commit 40453939c5a5aa16898d19bbac4d02f77196cc8b (v1.3.0-138-g4045393). - * Git branch regexp-canonicalize-lookup. + * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f). + * Git branch duk-config-improvements. * * See Duktape AUTHORS.rst and LICENSE.txt for copyright and * licensing information. @@ -218,9 +218,9 @@ struct duk_number_list_entry { * which Duktape snapshot was used. Not available in the Ecmascript * environment. */ -#define DUK_GIT_COMMIT "40453939c5a5aa16898d19bbac4d02f77196cc8b" -#define DUK_GIT_DESCRIBE "v1.3.0-138-g4045393" -#define DUK_GIT_BRANCH "regexp-canonicalize-lookup" +#define DUK_GIT_COMMIT "b7b1c5fd2d1d4550140d57e05a7b32f540082bfa" +#define DUK_GIT_DESCRIBE "v1.3.0-383-gb7b1c5f" +#define DUK_GIT_BRANCH "duk-config-improvements" /* Duktape debug protocol version used by this build. */ #define DUK_DEBUG_PROTOCOL_VERSION 1 @@ -242,6 +242,7 @@ struct duk_number_list_entry { #define DUK_API_ENTRY_STACK 64 /* Value types, used by e.g. duk_get_type() */ +#define DUK_TYPE_MIN 0 #define DUK_TYPE_NONE 0 /* no value, e.g. invalid index */ #define DUK_TYPE_UNDEFINED 1 /* Ecmascript undefined */ #define DUK_TYPE_NULL 2 /* Ecmascript null */ @@ -252,6 +253,7 @@ struct duk_number_list_entry { #define DUK_TYPE_BUFFER 7 /* fixed or dynamic, garbage collected byte buffer */ #define DUK_TYPE_POINTER 8 /* raw void pointer */ #define DUK_TYPE_LIGHTFUNC 9 /* lightweight function pointer */ +#define DUK_TYPE_MAX 9 /* Value mask types, used by e.g. duk_get_type_mask() */ #define DUK_TYPE_MASK_NONE (1 << DUK_TYPE_NONE) @@ -301,6 +303,12 @@ struct duk_number_list_entry { #define DUK_DEFPROP_HAVE_GETTER (1 << 7) /* set getter (given on value stack) */ #define DUK_DEFPROP_HAVE_SETTER (1 << 8) /* set setter (given on value stack) */ #define DUK_DEFPROP_FORCE (1 << 9) /* force change if possible, may still fail for e.g. virtual properties */ +#define DUK_DEFPROP_SET_WRITABLE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE) +#define DUK_DEFPROP_CLEAR_WRITABLE DUK_DEFPROP_HAVE_WRITABLE +#define DUK_DEFPROP_SET_ENUMERABLE (DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE) +#define DUK_DEFPROP_CLEAR_ENUMERABLE DUK_DEFPROP_HAVE_ENUMERABLE +#define DUK_DEFPROP_SET_CONFIGURABLE (DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE) +#define DUK_DEFPROP_CLEAR_CONFIGURABLE DUK_DEFPROP_HAVE_CONFIGURABLE /* Flags for duk_push_thread_raw() */ #define DUK_THREAD_NEW_GLOBAL_ENV (1 << 0) /* create a new global environment */ @@ -615,7 +623,8 @@ DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_id DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index); DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index); -DUK_EXTERNAL_DECL duk_bool_t duk_is_callable(duk_context *ctx, duk_idx_t index); +#define duk_is_callable(ctx,index) \ + duk_is_function((ctx), (index)) DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index); DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index); DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index); @@ -642,6 +651,18 @@ DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index); #define duk_is_error(ctx,index) \ (duk_get_error_code((ctx), (index)) != 0) +#define duk_is_eval_error(ctx,index) \ + (duk_get_error_code((ctx), (index)) == DUK_ERR_EVAL_ERROR) +#define duk_is_range_error(ctx,index) \ + (duk_get_error_code((ctx), (index)) == DUK_ERR_RANGE_ERROR) +#define duk_is_reference_error(ctx,index) \ + (duk_get_error_code((ctx), (index)) == DUK_ERR_REFERENCE_ERROR) +#define duk_is_syntax_error(ctx,index) \ + (duk_get_error_code((ctx), (index)) == DUK_ERR_SYNTAX_ERROR) +#define duk_is_type_error(ctx,index) \ + (duk_get_error_code((ctx), (index)) == DUK_ERR_TYPE_ERROR) +#define duk_is_uri_error(ctx,index) \ + (duk_get_error_code((ctx), (index)) == DUK_ERR_URI_ERROR) /* * Get operations: no coercion, returns default value for invalid @@ -686,6 +707,9 @@ DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t inde DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t index); DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index); DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index); +DUK_EXTERNAL_DECL void duk_require_function(duk_context *ctx, duk_idx_t index); +#define duk_require_callable(ctx,index) \ + duk_require_function((ctx), (index)) DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index); #define duk_require_object_coercible(ctx,index) \ @@ -1207,13 +1231,13 @@ DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx); union duk_double_union { double d; float f[2]; -#ifdef DUK_USE_64BIT_OPS +#if defined(DUK_USE_64BIT_OPS) duk_uint64_t ull[1]; #endif duk_uint32_t ui[2]; duk_uint16_t us[4]; duk_uint8_t uc[8]; -#ifdef DUK_USE_PACKED_TVAL_POSSIBLE +#if defined(DUK_USE_PACKED_TVAL) void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */ #endif }; -- cgit v1.2.3