summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <michael.drake@codethink.co.uk>2017-10-21 15:51:55 +0100
committerMichael Drake <michael.drake@codethink.co.uk>2017-10-21 15:51:55 +0100
commit3356906904487e5931e38ba21e100bdec113e783 (patch)
tree07135c1ccc898463c3cc35021941ee5ade5989ba
parentf7f18042bf00b431dbf2c8a93b0a6d7feb44f0d8 (diff)
downloadnetsurf-3356906904487e5931e38ba21e100bdec113e783.tar.gz
netsurf-3356906904487e5931e38ba21e100bdec113e783.tar.bz2
Duktape: Update to 2.2.0 release.
-rw-r--r--content/handlers/javascript/duktape/duk_config.h114
-rw-r--r--content/handlers/javascript/duktape/duktape.c26473
-rw-r--r--content/handlers/javascript/duktape/duktape.h179
3 files changed, 14327 insertions, 12439 deletions
diff --git a/content/handlers/javascript/duktape/duk_config.h b/content/handlers/javascript/duktape/duk_config.h
index 4a16a68da..1f2b1dab0 100644
--- a/content/handlers/javascript/duktape/duk_config.h
+++ b/content/handlers/javascript/duktape/duk_config.h
@@ -525,6 +525,11 @@
#endif
#elif defined(DUK_F_WINDOWS)
/* --- Windows --- */
+/* Windows version can't obviously be determined at compile time,
+ * but _WIN32_WINNT indicates the minimum version targeted:
+ * - https://msdn.microsoft.com/en-us/library/6sehtctf.aspx
+ */
+
/* 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.
@@ -535,17 +540,40 @@
/* Windows 32-bit and 64-bit are currently the same. */
/* MSVC does not have sys/param.h */
+
+#if defined(DUK_COMPILING_DUKTAPE)
+/* Only include when compiling Duktape to avoid polluting application build
+ * with a lot of unnecessary defines.
+ */
+#include <windows.h>
+#endif
+
+/* GetSystemTimePreciseAsFileTime() available from Windows 8:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=vs.85).aspx
+ */
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) || defined(DUK_USE_DATE_NOW_WINDOWS)
+/* User forced provider. */
+#else
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)
+#define DUK_USE_DATE_NOW_WINDOWS_SUBMS
+#else
#define DUK_USE_DATE_NOW_WINDOWS
+#endif
+#endif
+
#define DUK_USE_DATE_TZO_WINDOWS
+
/* Note: PRS and FMT are intentionally left undefined for now. This means
* there is no platform specific date parsing/formatting but there is still
* 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.
+
+/* QueryPerformanceCounter() may go backwards in Windows XP, so enable for
+ * Vista and later: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
*/
-#include <windows.h>
+#if !defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) && \
+ defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
+#define DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC
#endif
#define DUK_USE_OS_STRING "windows"
@@ -667,6 +695,10 @@
#define DUK_USE_DATE_PRS_STRPTIME
#define DUK_USE_DATE_FMT_STRFTIME
+#if 0 /* XXX: safe condition? */
+#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME
+#endif
+
#define DUK_USE_OS_STRING "linux"
#elif defined(DUK_F_SUN)
/* --- Solaris --- */
@@ -1307,7 +1339,16 @@
#endif
/* Avoid warning when doing DUK_UNREF(some_function). */
+#if defined(_MSC_VER) && (_MSC_VER < 1500)
+#pragma warning(disable: 4100 4101 4550 4551)
+#define DUK_UNREF(x)
+#else
#define DUK_UNREF(x) do { __pragma(warning(suppress:4100 4101 4550 4551)) (x); } while (0)
+#endif
+
+/* Older versions of MSVC don't support the LL/ULL suffix. */
+#define DUK_U64_CONSTANT(x) x##ui64
+#define DUK_I64_CONSTANT(x) x##i64
#elif defined(DUK_F_EMSCRIPTEN)
/* --- Emscripten --- */
#define DUK_NORETURN(decl) decl __attribute__((noreturn))
@@ -1535,12 +1576,14 @@
defined(DUK_F_BCC) || \
(defined(__WORDSIZE) && (__WORDSIZE == 32)) || \
((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \
- defined(DUK_F_HPUX)) && defined(_ILP32))
+ defined(DUK_F_HPUX)) && defined(_ILP32)) || \
+ defined(DUK_F_ARM32)
#define DUK_F_32BIT_PTRS
#elif defined(DUK_F_X64) || \
(defined(__WORDSIZE) && (__WORDSIZE == 64)) || \
((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \
- defined(DUK_F_HPUX)) && defined(_LP64))
+ defined(DUK_F_HPUX)) && defined(_LP64)) || \
+ defined(DUK_F_ARM64)
#define DUK_F_64BIT_PTRS
#else
/* not sure, not needed with C99 anyway */
@@ -1743,13 +1786,16 @@ typedef unsigned long long duk_uint64_t;
typedef signed long long duk_int64_t;
#endif
#endif
-#if !defined(DUK_F_HAVE_64BIT) && \
- (defined(DUK_F_MINGW) || defined(DUK_F_MSVC))
-/* Both MinGW and MSVC have a 64-bit type. */
+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MINGW)
#define DUK_F_HAVE_64BIT
typedef unsigned long duk_uint64_t;
typedef signed long duk_int64_t;
#endif
+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MSVC)
+#define DUK_F_HAVE_64BIT
+typedef unsigned __int64 duk_uint64_t;
+typedef signed __int64 duk_int64_t;
+#endif
#if !defined(DUK_F_HAVE_64BIT)
/* cannot detect 64-bit type, not always needed so don't error */
#endif
@@ -1957,8 +2003,8 @@ typedef duk_uint_fast16_t duk_small_uint_fast_t;
#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN
#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX
-/* Boolean values are represented with the platform 'int'. */
-typedef duk_small_int_t duk_bool_t;
+/* Boolean values are represented with the platform 'unsigned int'. */
+typedef duk_small_uint_t duk_bool_t;
#define DUK_BOOL_MIN DUK_SMALL_INT_MIN
#define DUK_BOOL_MAX DUK_SMALL_INT_MAX
@@ -2029,7 +2075,10 @@ typedef double duk_double_t;
#endif
#endif
-/* Type for public API calls. */
+/* Type used in public API declarations and user code. Typedef maps to
+ * 'struct duk_hthread' like the 'duk_hthread' typedef which is used
+ * exclusively in internals.
+ */
typedef struct duk_hthread duk_context;
/* Check whether we should use 64-bit integers or not.
@@ -2676,6 +2725,13 @@ typedef struct duk_hthread duk_context;
#undef DUK_USE_GCC_PRAGMAS
#endif
+#if !defined(DUK_U64_CONSTANT)
+#define DUK_U64_CONSTANT(x) x##ULL
+#endif
+#if !defined(DUK_I64_CONSTANT)
+#define DUK_I64_CONSTANT(x) x##LL
+#endif
+
/* Workaround for GH-323: avoid inlining control when compiling from
* multiple sources, as it causes compiler portability trouble.
*/
@@ -2773,6 +2829,9 @@ typedef struct duk_hthread duk_context;
#define DUK_USE_BUFFEROBJECT_SUPPORT
#undef DUK_USE_BUFLEN16
#define DUK_USE_BYTECODE_DUMP_SUPPORT
+#define DUK_USE_CACHE_ACTIVATION
+#define DUK_USE_CACHE_CATCHER
+#define DUK_USE_CALLSTACK_LIMIT 10000
#define DUK_USE_COMMONJS_MODULES
#define DUK_USE_COMPILER_RECLIMIT 2500
#define DUK_USE_COROUTINE_SUPPORT
@@ -2807,7 +2866,10 @@ typedef struct duk_hthread duk_context;
#define DUK_USE_ES6_PROXY
#define DUK_USE_ES6_REGEXP_SYNTAX
#define DUK_USE_ES6_UNICODE_ESCAPE
+#define DUK_USE_ES7
#define DUK_USE_ES7_EXP_OPERATOR
+#define DUK_USE_ES8
+#define DUK_USE_ES9
#define DUK_USE_ESBC_LIMITS
#define DUK_USE_ESBC_MAX_BYTES 2147418112L
#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L
@@ -2822,6 +2884,7 @@ typedef struct duk_hthread duk_context;
#undef DUK_USE_FASTINT
#define DUK_USE_FAST_REFCOUNT_DEFAULT
#undef DUK_USE_FATAL_HANDLER
+#define DUK_USE_FATAL_MAXLEN 128
#define DUK_USE_FINALIZER_SUPPORT
#undef DUK_USE_FINALIZER_TORTURE
#undef DUK_USE_FUNCPTR16
@@ -2831,6 +2894,7 @@ typedef struct duk_hthread duk_context;
#define DUK_USE_FUNC_FILENAME_PROPERTY
#define DUK_USE_FUNC_NAME_PROPERTY
#undef DUK_USE_GC_TORTURE
+#undef DUK_USE_GET_MONOTONIC_TIME
#undef DUK_USE_GET_RANDOM_DOUBLE
#undef DUK_USE_GLOBAL_BINDING
#define DUK_USE_GLOBAL_BUILTIN
@@ -2849,6 +2913,7 @@ typedef struct duk_hthread duk_context;
#define DUK_USE_HSTRING_ARRIDX
#define DUK_USE_HSTRING_CLEN
#undef DUK_USE_HSTRING_EXTDATA
+#define DUK_USE_HSTRING_LAZY_CLEN
#define DUK_USE_HTML_COMMENTS
#define DUK_USE_IDCHAR_FASTPATH
#undef DUK_USE_INJECT_HEAP_ALLOC_ERROR
@@ -2885,12 +2950,15 @@ typedef struct duk_hthread duk_context;
#undef DUK_USE_OBJSIZES16
#undef DUK_USE_PARANOID_ERRORS
#define DUK_USE_PC2LINE
+#define DUK_USE_PERFORMANCE_BUILTIN
#undef DUK_USE_PREFER_SIZE
+#undef DUK_USE_PROMISE_BUILTIN
#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS
#undef DUK_USE_REFCOUNT16
#define DUK_USE_REFCOUNT32
#define DUK_USE_REFERENCE_COUNTING
#define DUK_USE_REFLECT_BUILTIN
+#define DUK_USE_REGEXP_CANON_BITMAP
#undef DUK_USE_REGEXP_CANON_WORKAROUND
#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000
#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000
@@ -2925,6 +2993,10 @@ typedef struct duk_hthread duk_context;
#define DUK_USE_TRACEBACKS
#define DUK_USE_TRACEBACK_DEPTH 10
#define DUK_USE_USER_DECLARE() /* no user declarations */
+#define DUK_USE_VALSTACK_GROW_SHIFT 2
+#define DUK_USE_VALSTACK_LIMIT 1000000L
+#define DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT 2
+#define DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT 4
#undef DUK_USE_VALSTACK_UNSAFE
#define DUK_USE_VERBOSE_ERRORS
#define DUK_USE_VERBOSE_EXECUTOR_ERRORS
@@ -2958,11 +3030,13 @@ typedef struct duk_hthread duk_context;
#if defined(DUK_USE_DATE_GET_NOW)
/* External provider already defined. */
#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday()
#elif defined(DUK_USE_DATE_NOW_TIME)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time()
#elif defined(DUK_USE_DATE_NOW_WINDOWS)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx))
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows()
+#elif defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows_subms()
#else
#error no provider for DUK_USE_DATE_GET_NOW()
#endif
@@ -2998,6 +3072,16 @@ typedef struct duk_hthread duk_context;
/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */
#endif
+#if defined(DUK_USE_GET_MONOTONIC_TIME)
+/* External provider already defined. */
+#elif defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_clock_gettime()
+#elif defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_windows_qpc()
+#else
+/* No provider for DUK_USE_GET_MONOTONIC_TIME(), fall back to DUK_USE_DATE_GET_NOW(). */
+#endif
+
#endif /* DUK_COMPILING_DUKTAPE */
/*
diff --git a/content/handlers/javascript/duktape/duktape.c b/content/handlers/javascript/duktape/duktape.c
index c031de021..3171c6e23 100644
--- a/content/handlers/javascript/duktape/duktape.c
+++ b/content/handlers/javascript/duktape/duktape.c
@@ -1,7 +1,5 @@
-/* Omit from static analysis. */
-#ifndef __clang_analyzer__
/*
- * Single source autogenerated distributable for Duktape 2.1.0.
+ * Single source autogenerated distributable for Duktape 2.2.0.
*
* Git commit external (external).
* Git branch external.
@@ -86,6 +84,9 @@
* * Remko Tron\u00e7on (https://el-tramo.be)
* * Romero Malaquias (rbsm@ic.ufal.br)
* * Michael Drake <michael.drake@codethink.co.uk>
+* * Steven Don (https://github.com/shdon)
+* * Simon Stone (https://github.com/sstone1)
+* * \J. McC. (https://github.com/jmhmccr)
*
* Other contributions
* ===================
@@ -410,47 +411,47 @@ typedef union duk_double_union duk_double_union;
#if defined(DUK_USE_DOUBLE_ME)
/* Macros for 64-bit ops + mixed endian doubles. */
#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = 0x000000007ff80000ULL; \
+ (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \
} while (0)
#define DUK__DBLUNION_IS_NAN_FULL(u) \
- ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL) && \
- ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0))
+ ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \
+ ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0))
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000))
#define DUK__DBLUNION_IS_ANYINF(u) \
- (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x000000007ff00000ULL)
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000))
#define DUK__DBLUNION_IS_POSINF(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff00000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000))
#define DUK__DBLUNION_IS_NEGINF(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x00000000fff00000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000))
#define DUK__DBLUNION_IS_ANYZERO(u) \
- (((u)->ull[DUK_DBL_IDX_ULL0] & 0xffffffff7fffffffULL) == 0x0000000000000000ULL)
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_POSZERO(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_NEGZERO(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000080000000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000))
#else
/* Macros for 64-bit ops + big/little endian doubles. */
#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \
+ (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \
} while (0)
#define DUK__DBLUNION_IS_NAN_FULL(u) \
- ((((u)->ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000UL) && \
- ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0))
+ ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \
+ ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0))
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000))
#define DUK__DBLUNION_IS_ANYINF(u) \
- (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x7ff0000000000000ULL)
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000))
#define DUK__DBLUNION_IS_POSINF(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff0000000000000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000))
#define DUK__DBLUNION_IS_NEGINF(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0xfff0000000000000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000))
#define DUK__DBLUNION_IS_ANYZERO(u) \
- (((u)->ull[DUK_DBL_IDX_ULL0] & 0x7fffffffffffffffULL) == 0x0000000000000000ULL)
+ (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_POSZERO(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x0000000000000000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_NEGZERO(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x8000000000000000ULL)
+ ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000))
#endif
#else /* DUK_USE_64BIT_OPS */
/* Macros for no 64-bit ops, any endianness. */
@@ -597,7 +598,7 @@ typedef union duk_double_union duk_double_union;
/* Some sign bit helpers. */
#if defined(DUK_USE_64BIT_OPS)
-#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & 0x8000000000000000ULL) != 0)
+#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0)
#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U))
#else
#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0)
@@ -706,10 +707,12 @@ struct duk_hstring_external;
struct duk_hobject;
struct duk_hcompfunc;
struct duk_hnatfunc;
+struct duk_hboundfunc;
struct duk_hthread;
struct duk_hbufobj;
struct duk_hdecenv;
struct duk_hobjenv;
+struct duk_hproxy;
struct duk_hbuffer;
struct duk_hbuffer_fixed;
struct duk_hbuffer_dynamic;
@@ -764,10 +767,12 @@ typedef struct duk_hstring_external duk_hstring_external;
typedef struct duk_hobject duk_hobject;
typedef struct duk_hcompfunc duk_hcompfunc;
typedef struct duk_hnatfunc duk_hnatfunc;
+typedef struct duk_hboundfunc duk_hboundfunc;
typedef struct duk_hthread duk_hthread;
typedef struct duk_hbufobj duk_hbufobj;
typedef struct duk_hdecenv duk_hdecenv;
typedef struct duk_hobjenv duk_hobjenv;
+typedef struct duk_hproxy duk_hproxy;
typedef struct duk_hbuffer duk_hbuffer;
typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
@@ -942,7 +947,7 @@ typedef struct {
} while (0)
#else
#define DUK__TVAL_SET_I48(tv,i) do { \
- (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
+ (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \
} while (0)
#define DUK__TVAL_SET_U32(tv,i) do { \
(tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
@@ -1039,7 +1044,7 @@ typedef struct {
#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
/* getters */
-#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_int_t) (tv)->us[DUK_DBL_IDX_US1])
+#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1])
#if defined(DUK_USE_FASTINT)
#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv))
@@ -1055,7 +1060,7 @@ typedef struct {
(out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \
} while (0)
#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1]))
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_int_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
+#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1])
#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1])
#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1])
@@ -1193,7 +1198,7 @@ typedef struct {
duk_tval *duk__tv; \
duk__tv = (tv); \
duk__tv->t = DUK_TAG_BOOLEAN; \
- duk__tv->v.i = (val); \
+ duk__tv->v.i = (duk_small_int_t) (val); \
} while (0)
#if defined(DUK_USE_FASTINT)
@@ -1324,7 +1329,7 @@ typedef struct {
#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
/* getters */
-#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
+#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i)
#if defined(DUK_USE_FASTINT)
#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
@@ -1351,7 +1356,7 @@ typedef struct {
(out_fp) = (tv)->v.lightfunc; \
} while (0)
#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
+#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra))
#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
@@ -1394,7 +1399,7 @@ typedef struct {
#if 0
DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
#endif
-DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
+DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
#endif
#endif /* DUK_USE_PACKED_TVAL */
@@ -1416,11 +1421,11 @@ DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(d
#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8))
#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
- (((lf_flags) >> 4) & 0x0f)
+ (((lf_flags) >> 4) & 0x0fU)
#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
- ((lf_flags) & 0x0f)
+ ((lf_flags) & 0x0fU)
#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
- (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
+ ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs)
#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
#define DUK_LFUNC_NARGS_MIN 0x00
@@ -1432,11 +1437,11 @@ DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(d
/* fastint constants etc */
#if defined(DUK_USE_FASTINT)
-#define DUK_FASTINT_MIN (-0x800000000000LL)
-#define DUK_FASTINT_MAX 0x7fffffffffffLL
+#define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000))
+#define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff))
#define DUK_FASTINT_BITS 48
-DUK_INTERNAL_DECL DUK_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x);
+DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x);
DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x);
#endif
@@ -1662,302 +1667,296 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double
#define DUK_STRIDX_CALLER 69 /* 'caller' */
#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
-#define DUK_STRIDX_DELETE_PROPERTY 70 /* 'deleteProperty' */
+#define DUK_STRIDX_APPLY 70 /* 'apply' */
+#define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
+#define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
+#define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */
+#define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT)
+#define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT)
+#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
-#define DUK_STRIDX_GET 71 /* 'get' */
+#define DUK_STRIDX_GET 73 /* 'get' */
#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
-#define DUK_STRIDX_HAS 72 /* 'has' */
+#define DUK_STRIDX_HAS 74 /* 'has' */
#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
-#define DUK_STRIDX_OWN_KEYS 73 /* 'ownKeys' */
+#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */
#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
-#define DUK_STRIDX_SET_PROTOTYPE_OF 74 /* 'setPrototypeOf' */
+#define DUK_STRIDX_SET_PROTOTYPE_OF 76 /* 'setPrototypeOf' */
#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
-#define DUK_STRIDX___PROTO__ 75 /* '__proto__' */
+#define DUK_STRIDX___PROTO__ 77 /* '__proto__' */
#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
-#define DUK_STRIDX_TO_STRING 76 /* 'toString' */
+#define DUK_STRIDX_TO_STRING 78 /* 'toString' */
#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
-#define DUK_STRIDX_TO_JSON 77 /* 'toJSON' */
+#define DUK_STRIDX_TO_JSON 79 /* 'toJSON' */
#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
-#define DUK_STRIDX_TYPE 78 /* 'type' */
+#define DUK_STRIDX_TYPE 80 /* 'type' */
#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
-#define DUK_STRIDX_DATA 79 /* 'data' */
+#define DUK_STRIDX_DATA 81 /* 'data' */
#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
-#define DUK_STRIDX_LENGTH 80 /* 'length' */
+#define DUK_STRIDX_LENGTH 82 /* 'length' */
#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
-#define DUK_STRIDX_SET 81 /* 'set' */
+#define DUK_STRIDX_SET 83 /* 'set' */
#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
-#define DUK_STRIDX_STACK 82 /* 'stack' */
+#define DUK_STRIDX_STACK 84 /* 'stack' */
#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
-#define DUK_STRIDX_PC 83 /* 'pc' */
+#define DUK_STRIDX_PC 85 /* 'pc' */
#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
-#define DUK_STRIDX_LINE_NUMBER 84 /* 'lineNumber' */
+#define DUK_STRIDX_LINE_NUMBER 86 /* 'lineNumber' */
#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
-#define DUK_STRIDX_INT_TRACEDATA 85 /* '\xffTracedata' */
+#define DUK_STRIDX_INT_TRACEDATA 87 /* '\x82Tracedata' */
#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
-#define DUK_STRIDX_NAME 86 /* 'name' */
+#define DUK_STRIDX_NAME 88 /* 'name' */
#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
-#define DUK_STRIDX_FILE_NAME 87 /* 'fileName' */
+#define DUK_STRIDX_FILE_NAME 89 /* 'fileName' */
#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
-#define DUK_STRIDX_LC_POINTER 88 /* 'pointer' */
+#define DUK_STRIDX_LC_POINTER 90 /* 'pointer' */
#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
-#define DUK_STRIDX_INT_VALUE 89 /* '\xffValue' */
-#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
-#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
-#define DUK_STRIDX_INT_NEXT 90 /* '\xffNext' */
+#define DUK_STRIDX_INT_TARGET 91 /* '\x82Target' */
+#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
+#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
+#define DUK_STRIDX_INT_NEXT 92 /* '\x82Next' */
#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
-#define DUK_STRIDX_INT_BYTECODE 91 /* '\xffBytecode' */
+#define DUK_STRIDX_INT_BYTECODE 93 /* '\x82Bytecode' */
#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
-#define DUK_STRIDX_INT_FORMALS 92 /* '\xffFormals' */
+#define DUK_STRIDX_INT_FORMALS 94 /* '\x82Formals' */
#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
-#define DUK_STRIDX_INT_VARMAP 93 /* '\xffVarmap' */
+#define DUK_STRIDX_INT_VARMAP 95 /* '\x82Varmap' */
#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
-#define DUK_STRIDX_INT_SOURCE 94 /* '\xffSource' */
+#define DUK_STRIDX_INT_SOURCE 96 /* '\x82Source' */
#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
-#define DUK_STRIDX_INT_PC2LINE 95 /* '\xffPc2line' */
+#define DUK_STRIDX_INT_PC2LINE 97 /* '\x82Pc2line' */
#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
-#define DUK_STRIDX_INT_THIS 96 /* '\xffThis' */
-#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
-#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
-#define DUK_STRIDX_INT_ARGS 97 /* '\xffArgs' */
-#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
-#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
-#define DUK_STRIDX_INT_MAP 98 /* '\xffMap' */
+#define DUK_STRIDX_INT_MAP 98 /* '\x82Map' */
#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
-#define DUK_STRIDX_INT_VARENV 99 /* '\xffVarenv' */
+#define DUK_STRIDX_INT_VARENV 99 /* '\x82Varenv' */
#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
-#define DUK_STRIDX_INT_FINALIZER 100 /* '\xffFinalizer' */
+#define DUK_STRIDX_INT_FINALIZER 100 /* '\x82Finalizer' */
#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
-#define DUK_STRIDX_INT_TARGET 101 /* '\xffTarget' */
-#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
-#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
-#define DUK_STRIDX_INT_HANDLER 102 /* '\xffHandler' */
-#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER)
-#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER)
-#define DUK_STRIDX_COMPILE 103 /* 'compile' */
+#define DUK_STRIDX_INT_VALUE 101 /* '\x82Value' */
+#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
+#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
+#define DUK_STRIDX_COMPILE 102 /* 'compile' */
#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
-#define DUK_STRIDX_INPUT 104 /* 'input' */
+#define DUK_STRIDX_INPUT 103 /* 'input' */
#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
-#define DUK_STRIDX_ERR_CREATE 105 /* 'errCreate' */
+#define DUK_STRIDX_ERR_CREATE 104 /* 'errCreate' */
#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
-#define DUK_STRIDX_ERR_THROW 106 /* 'errThrow' */
+#define DUK_STRIDX_ERR_THROW 105 /* 'errThrow' */
#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
-#define DUK_STRIDX_ENV 107 /* 'env' */
+#define DUK_STRIDX_ENV 106 /* 'env' */
#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
-#define DUK_STRIDX_HEX 108 /* 'hex' */
+#define DUK_STRIDX_HEX 107 /* 'hex' */
#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
-#define DUK_STRIDX_BASE64 109 /* 'base64' */
+#define DUK_STRIDX_BASE64 108 /* 'base64' */
#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
-#define DUK_STRIDX_JX 110 /* 'jx' */
+#define DUK_STRIDX_JX 109 /* 'jx' */
#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
-#define DUK_STRIDX_JC 111 /* 'jc' */
+#define DUK_STRIDX_JC 110 /* 'jc' */
#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
-#define DUK_STRIDX_RESUME 112 /* 'resume' */
-#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
-#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
-#define DUK_STRIDX_JSON_EXT_UNDEFINED 113 /* '{"_undef":true}' */
+#define DUK_STRIDX_JSON_EXT_UNDEFINED 111 /* '{"_undef":true}' */
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
-#define DUK_STRIDX_JSON_EXT_NAN 114 /* '{"_nan":true}' */
+#define DUK_STRIDX_JSON_EXT_NAN 112 /* '{"_nan":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
-#define DUK_STRIDX_JSON_EXT_POSINF 115 /* '{"_inf":true}' */
+#define DUK_STRIDX_JSON_EXT_POSINF 113 /* '{"_inf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
-#define DUK_STRIDX_JSON_EXT_NEGINF 116 /* '{"_ninf":true}' */
+#define DUK_STRIDX_JSON_EXT_NEGINF 114 /* '{"_ninf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
-#define DUK_STRIDX_JSON_EXT_FUNCTION1 117 /* '{"_func":true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION1 115 /* '{"_func":true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
-#define DUK_STRIDX_JSON_EXT_FUNCTION2 118 /* '{_func:true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION2 116 /* '{_func:true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
-#define DUK_STRIDX_BREAK 119 /* 'break' */
+#define DUK_STRIDX_BREAK 117 /* 'break' */
#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
-#define DUK_STRIDX_CASE 120 /* 'case' */
+#define DUK_STRIDX_CASE 118 /* 'case' */
#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
-#define DUK_STRIDX_CATCH 121 /* 'catch' */
+#define DUK_STRIDX_CATCH 119 /* 'catch' */
#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
-#define DUK_STRIDX_CONTINUE 122 /* 'continue' */
+#define DUK_STRIDX_CONTINUE 120 /* 'continue' */
#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
-#define DUK_STRIDX_DEBUGGER 123 /* 'debugger' */
+#define DUK_STRIDX_DEBUGGER 121 /* 'debugger' */
#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
-#define DUK_STRIDX_DEFAULT 124 /* 'default' */
+#define DUK_STRIDX_DEFAULT 122 /* 'default' */
#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
-#define DUK_STRIDX_DELETE 125 /* 'delete' */
+#define DUK_STRIDX_DELETE 123 /* 'delete' */
#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
-#define DUK_STRIDX_DO 126 /* 'do' */
+#define DUK_STRIDX_DO 124 /* 'do' */
#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
-#define DUK_STRIDX_ELSE 127 /* 'else' */
+#define DUK_STRIDX_ELSE 125 /* 'else' */
#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
-#define DUK_STRIDX_FINALLY 128 /* 'finally' */
+#define DUK_STRIDX_FINALLY 126 /* 'finally' */
#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
-#define DUK_STRIDX_FOR 129 /* 'for' */
+#define DUK_STRIDX_FOR 127 /* 'for' */
#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
-#define DUK_STRIDX_LC_FUNCTION 130 /* 'function' */
+#define DUK_STRIDX_LC_FUNCTION 128 /* 'function' */
#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
-#define DUK_STRIDX_IF 131 /* 'if' */
+#define DUK_STRIDX_IF 129 /* 'if' */
#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
-#define DUK_STRIDX_IN 132 /* 'in' */
+#define DUK_STRIDX_IN 130 /* 'in' */
#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
-#define DUK_STRIDX_INSTANCEOF 133 /* 'instanceof' */
+#define DUK_STRIDX_INSTANCEOF 131 /* 'instanceof' */
#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
-#define DUK_STRIDX_NEW 134 /* 'new' */
+#define DUK_STRIDX_NEW 132 /* 'new' */
#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
-#define DUK_STRIDX_RETURN 135 /* 'return' */
+#define DUK_STRIDX_RETURN 133 /* 'return' */
#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
-#define DUK_STRIDX_SWITCH 136 /* 'switch' */
+#define DUK_STRIDX_SWITCH 134 /* 'switch' */
#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
-#define DUK_STRIDX_THIS 137 /* 'this' */
+#define DUK_STRIDX_THIS 135 /* 'this' */
#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
-#define DUK_STRIDX_THROW 138 /* 'throw' */
+#define DUK_STRIDX_THROW 136 /* 'throw' */
#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
-#define DUK_STRIDX_TRY 139 /* 'try' */
+#define DUK_STRIDX_TRY 137 /* 'try' */
#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
-#define DUK_STRIDX_TYPEOF 140 /* 'typeof' */
+#define DUK_STRIDX_TYPEOF 138 /* 'typeof' */
#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
-#define DUK_STRIDX_VAR 141 /* 'var' */
+#define DUK_STRIDX_VAR 139 /* 'var' */
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
-#define DUK_STRIDX_CONST 142 /* 'const' */
+#define DUK_STRIDX_CONST 140 /* 'const' */
#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
-#define DUK_STRIDX_VOID 143 /* 'void' */
+#define DUK_STRIDX_VOID 141 /* 'void' */
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
-#define DUK_STRIDX_WHILE 144 /* 'while' */
+#define DUK_STRIDX_WHILE 142 /* 'while' */
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
-#define DUK_STRIDX_WITH 145 /* 'with' */
+#define DUK_STRIDX_WITH 143 /* 'with' */
#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
-#define DUK_STRIDX_CLASS 146 /* 'class' */
+#define DUK_STRIDX_CLASS 144 /* 'class' */
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_STRIDX_ENUM 147 /* 'enum' */
+#define DUK_STRIDX_ENUM 145 /* 'enum' */
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
-#define DUK_STRIDX_EXPORT 148 /* 'export' */
+#define DUK_STRIDX_EXPORT 146 /* 'export' */
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
-#define DUK_STRIDX_EXTENDS 149 /* 'extends' */
+#define DUK_STRIDX_EXTENDS 147 /* 'extends' */
#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
-#define DUK_STRIDX_IMPORT 150 /* 'import' */
+#define DUK_STRIDX_IMPORT 148 /* 'import' */
#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
-#define DUK_STRIDX_SUPER 151 /* 'super' */
+#define DUK_STRIDX_SUPER 149 /* 'super' */
#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
-#define DUK_STRIDX_LC_NULL 152 /* 'null' */
+#define DUK_STRIDX_LC_NULL 150 /* 'null' */
#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
-#define DUK_STRIDX_TRUE 153 /* 'true' */
+#define DUK_STRIDX_TRUE 151 /* 'true' */
#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
-#define DUK_STRIDX_FALSE 154 /* 'false' */
+#define DUK_STRIDX_FALSE 152 /* 'false' */
#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
-#define DUK_STRIDX_IMPLEMENTS 155 /* 'implements' */
+#define DUK_STRIDX_IMPLEMENTS 153 /* 'implements' */
#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
-#define DUK_STRIDX_INTERFACE 156 /* 'interface' */
+#define DUK_STRIDX_INTERFACE 154 /* 'interface' */
#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
-#define DUK_STRIDX_LET 157 /* 'let' */
+#define DUK_STRIDX_LET 155 /* 'let' */
#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
-#define DUK_STRIDX_PACKAGE 158 /* 'package' */
+#define DUK_STRIDX_PACKAGE 156 /* 'package' */
#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
-#define DUK_STRIDX_PRIVATE 159 /* 'private' */
+#define DUK_STRIDX_PRIVATE 157 /* 'private' */
#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
-#define DUK_STRIDX_PROTECTED 160 /* 'protected' */
+#define DUK_STRIDX_PROTECTED 158 /* 'protected' */
#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
-#define DUK_STRIDX_PUBLIC 161 /* 'public' */
+#define DUK_STRIDX_PUBLIC 159 /* 'public' */
#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
-#define DUK_STRIDX_STATIC 162 /* 'static' */
+#define DUK_STRIDX_STATIC 160 /* 'static' */
#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
-#define DUK_STRIDX_YIELD 163 /* 'yield' */
+#define DUK_STRIDX_YIELD 161 /* 'yield' */
#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
-#define DUK_HEAP_NUM_STRINGS 164
-#define DUK_STRIDX_START_RESERVED 119
-#define DUK_STRIDX_START_STRICT_RESERVED 155
-#define DUK_STRIDX_END_RESERVED 164 /* exclusive endpoint */
+#define DUK_HEAP_NUM_STRINGS 162
+#define DUK_STRIDX_START_RESERVED 117
+#define DUK_STRIDX_START_STRICT_RESERVED 153
+#define DUK_STRIDX_END_RESERVED 162 /* exclusive endpoint */
/* To convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[903];
+DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[892];
#endif /* !DUK_SINGLE_FILE */
#define DUK_STRDATA_MAX_STRLEN 17
-#define DUK_STRDATA_DATA_LENGTH 903
+#define DUK_STRDATA_DATA_LENGTH 892
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
@@ -2013,10 +2012,14 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
@@ -2083,10 +2086,13 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
@@ -2100,6 +2106,8 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx);
@@ -2128,8 +2136,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_con
DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx);
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[166];
+DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176];
#endif /* !DUK_SINGLE_FILE */
#define DUK_BIDX_GLOBAL 0
#define DUK_BIDX_GLOBAL_ENV 1
@@ -2137,92 +2146,69 @@ DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[166];
#define DUK_BIDX_OBJECT_PROTOTYPE 3
#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
#define DUK_BIDX_FUNCTION_PROTOTYPE 5
-#define DUK_BIDX_ARRAY_CONSTRUCTOR 6
-#define DUK_BIDX_ARRAY_PROTOTYPE 7
-#define DUK_BIDX_STRING_CONSTRUCTOR 8
-#define DUK_BIDX_STRING_PROTOTYPE 9
-#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10
-#define DUK_BIDX_BOOLEAN_PROTOTYPE 11
-#define DUK_BIDX_NUMBER_CONSTRUCTOR 12
-#define DUK_BIDX_NUMBER_PROTOTYPE 13
-#define DUK_BIDX_DATE_CONSTRUCTOR 14
-#define DUK_BIDX_DATE_PROTOTYPE 15
-#define DUK_BIDX_REGEXP_CONSTRUCTOR 16
-#define DUK_BIDX_REGEXP_PROTOTYPE 17
-#define DUK_BIDX_ERROR_CONSTRUCTOR 18
-#define DUK_BIDX_ERROR_PROTOTYPE 19
-#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20
-#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21
-#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22
-#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23
-#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24
-#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25
-#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26
-#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27
-#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28
-#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29
-#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30
-#define DUK_BIDX_URI_ERROR_PROTOTYPE 31
-#define DUK_BIDX_MATH 32
-#define DUK_BIDX_JSON 33
-#define DUK_BIDX_TYPE_ERROR_THROWER 34
-#define DUK_BIDX_DUKTAPE 35
-#define DUK_BIDX_THREAD_CONSTRUCTOR 36
-#define DUK_BIDX_THREAD_PROTOTYPE 37
-#define DUK_BIDX_POINTER_CONSTRUCTOR 38
-#define DUK_BIDX_POINTER_PROTOTYPE 39
-#define DUK_BIDX_DOUBLE_ERROR 40
-#define DUK_BIDX_PROXY_CONSTRUCTOR 41
-#define DUK_BIDX_REFLECT 42
-#define DUK_BIDX_SYMBOL_PROTOTYPE 43
-#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 44
-#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 45
-#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 46
-#define DUK_BIDX_DATAVIEW_PROTOTYPE 47
-#define DUK_BIDX_TYPEDARRAY_CONSTRUCTOR 48
-#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 49
-#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 50
-#define DUK_BIDX_INT8ARRAY_PROTOTYPE 51
-#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 52
-#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 53
-#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 54
-#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 55
-#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 56
-#define DUK_BIDX_INT16ARRAY_PROTOTYPE 57
-#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 58
-#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 59
-#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 60
-#define DUK_BIDX_INT32ARRAY_PROTOTYPE 61
-#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 62
-#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 63
-#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 64
-#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 65
-#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 66
-#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 67
-#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 68
-#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 69
-#define DUK_BIDX_TEXTENCODER_CONSTRUCTOR 70
-#define DUK_BIDX_TEXTENCODER_PROTOTYPE 71
-#define DUK_BIDX_TEXTDECODER_CONSTRUCTOR 72
-#define DUK_BIDX_TEXTDECODER_PROTOTYPE 73
-#define DUK_NUM_BUILTINS 74
-#define DUK_NUM_BIDX_BUILTINS 74
-#define DUK_NUM_ALL_BUILTINS 74
+#define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE 6
+#define DUK_BIDX_ARRAY_CONSTRUCTOR 7
+#define DUK_BIDX_ARRAY_PROTOTYPE 8
+#define DUK_BIDX_STRING_CONSTRUCTOR 9
+#define DUK_BIDX_STRING_PROTOTYPE 10
+#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 11
+#define DUK_BIDX_BOOLEAN_PROTOTYPE 12
+#define DUK_BIDX_NUMBER_CONSTRUCTOR 13
+#define DUK_BIDX_NUMBER_PROTOTYPE 14
+#define DUK_BIDX_DATE_CONSTRUCTOR 15
+#define DUK_BIDX_DATE_PROTOTYPE 16
+#define DUK_BIDX_REGEXP_CONSTRUCTOR 17
+#define DUK_BIDX_REGEXP_PROTOTYPE 18
+#define DUK_BIDX_ERROR_CONSTRUCTOR 19
+#define DUK_BIDX_ERROR_PROTOTYPE 20
+#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 21
+#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 22
+#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 23
+#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 24
+#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 25
+#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 26
+#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 27
+#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 28
+#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 29
+#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 30
+#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 31
+#define DUK_BIDX_URI_ERROR_PROTOTYPE 32
+#define DUK_BIDX_TYPE_ERROR_THROWER 33
+#define DUK_BIDX_DUKTAPE 34
+#define DUK_BIDX_THREAD_PROTOTYPE 35
+#define DUK_BIDX_POINTER_PROTOTYPE 36
+#define DUK_BIDX_DOUBLE_ERROR 37
+#define DUK_BIDX_SYMBOL_PROTOTYPE 38
+#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 39
+#define DUK_BIDX_DATAVIEW_PROTOTYPE 40
+#define DUK_BIDX_INT8ARRAY_PROTOTYPE 41
+#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 42
+#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 43
+#define DUK_BIDX_INT16ARRAY_PROTOTYPE 44
+#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 45
+#define DUK_BIDX_INT32ARRAY_PROTOTYPE 46
+#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 47
+#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 48
+#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 49
+#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50
+#define DUK_NUM_BUILTINS 51
+#define DUK_NUM_BIDX_BUILTINS 51
+#define DUK_NUM_ALL_BUILTINS 76
#if defined(DUK_USE_DOUBLE_LE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3819
+#define DUK_BUILTINS_DATA_LENGTH 3972
#elif defined(DUK_USE_DOUBLE_BE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3819
+#define DUK_BUILTINS_DATA_LENGTH 3972
#elif defined(DUK_USE_DOUBLE_ME)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3819];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3819
+#define DUK_BUILTINS_DATA_LENGTH 3972
#else
#error invalid endianness defines
#endif
@@ -2337,10 +2323,10 @@ struct duk_bitencoder_ctx {
/*
* Buffer writer (dynamic buffer only)
*
- * Helper for writing to a dynamic buffer with a concept of a "spare" area
+ * Helper for writing to a dynamic buffer with a concept of a "slack" area
* to reduce resizes. You can ensure there is enough space beforehand and
* then write for a while without further checks, relying on a stable data
- * pointer. Spare handling is automatic so call sites only indicate how
+ * pointer. Slack handling is automatic so call sites only indicate how
* much data they need right now.
*
* There are several ways to write using bufwriter. The best approach
@@ -2366,8 +2352,13 @@ struct duk_bufwriter_ctx {
duk_hbuffer_dynamic *buf;
};
-#define DUK_BW_SPARE_ADD 64
-#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */
+#if defined(DUK_USE_PREFER_SIZE)
+#define DUK_BW_SLACK_ADD 64
+#define DUK_BW_SLACK_SHIFT 4 /* 2^4 -> 1/16 = 6.25% slack */
+#else
+#define DUK_BW_SLACK_ADD 64
+#define DUK_BW_SLACK_SHIFT 2 /* 2^2 -> 1/4 = 25% slack */
+#endif
/* Initialization and finalization (compaction), converting to other types. */
@@ -2382,7 +2373,7 @@ struct duk_bufwriter_ctx {
duk_bw_compact((thr), (bw_ctx)); \
} while (0)
#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
- duk_push_lstring((duk_context *) (thr), \
+ duk_push_lstring((thr), \
(const char *) (bw_ctx)->p_base, \
(duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
} while (0)
@@ -2465,7 +2456,7 @@ struct duk_bufwriter_ctx {
duk_bw_compact((thr), (bw_ctx)); \
} while (0)
-/* Fast write calls which assume you control the spare beforehand.
+/* Fast write calls which assume you control the slack beforehand.
* Multibyte write variants exist and use a temporary write pointer
* because byte writes alias with anything: with a stored pointer
* explicit pointer load/stores get generated (e.g. gcc -Os).
@@ -2528,7 +2519,7 @@ struct duk_bufwriter_ctx {
#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
duk_ucodepoint_t duk__cp; \
duk_small_int_t duk__enc_len; \
- duk__cp = (cp); \
+ duk__cp = (duk_ucodepoint_t) (cp); \
DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
(bw_ctx)->p += duk__enc_len; \
@@ -2762,12 +2753,12 @@ DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_b
DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
-DUK_INTERNAL_DECL DUK_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
+DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
+DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
+DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
+DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
@@ -2854,10 +2845,17 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
#define DUK_STR_BUFFER_TOO_LONG "buffer too long"
#define DUK_STR_ALLOC_FAILED "alloc failed"
#define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type"
-#define DUK_STR_ENCODE_FAILED "encode failed"
-#define DUK_STR_DECODE_FAILED "decode failed"
+#define DUK_STR_BASE64_ENCODE_FAILED "base64 encode failed"
+#define DUK_STR_SOURCE_DECODE_FAILED "source decode failed"
+#define DUK_STR_UTF8_DECODE_FAILED "utf-8 decode failed"
+#define DUK_STR_BASE64_DECODE_FAILED "base64 decode failed"
+#define DUK_STR_HEX_DECODE_FAILED "hex decode failed"
+#define DUK_STR_INVALID_BYTECODE "invalid bytecode"
#define DUK_STR_NO_SOURCECODE "no sourcecode"
#define DUK_STR_RESULT_TOO_LONG "result too long"
+#define DUK_STR_INVALID_CFUNC_RC "invalid C function rc"
+#define DUK_STR_INVALID_INSTANCEOF_RVAL "invalid instanceof rval"
+#define DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO "instanceof rval has no .prototype"
/* JSON */
#define DUK_STR_FMT_PTR "%p"
@@ -2867,7 +2865,6 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
#define DUK_STR_CYCLIC_INPUT "cyclic input"
/* Object property access */
-#define DUK_STR_PROXY_REVOKED "proxy revoked"
#define DUK_STR_INVALID_BASE "invalid base value"
#define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'"
#define DUK_STR_PROXY_REJECTED "proxy rejected"
@@ -2876,6 +2873,7 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
#define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor"
/* Proxy */
+#define DUK_STR_PROXY_REVOKED "proxy revoked"
#define DUK_STR_INVALID_TRAP_RESULT "invalid trap result"
/* Variables */
@@ -2900,6 +2898,7 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
#define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier"
#define DUK_STR_INVALID_EXPRESSION "invalid expression"
#define DUK_STR_INVALID_LVALUE "invalid lvalue"
+#define DUK_STR_INVALID_NEWTARGET "invalid new.target"
#define DUK_STR_EXPECTED_IDENTIFIER "expected identifier"
#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed"
#define DUK_STR_INVALID_FOR "invalid for statement"
@@ -2916,7 +2915,7 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
#define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name"
#define DUK_STR_FUNC_NAME_REQUIRED "function name required"
-/* Regexp */
+/* RegExp */
#define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier"
#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom"
#define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)"
@@ -2935,7 +2934,6 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
/* Limits */
#define DUK_STR_VALSTACK_LIMIT "valstack limit"
#define DUK_STR_CALLSTACK_LIMIT "callstack limit"
-#define DUK_STR_CATCHSTACK_LIMIT "catchstack limit"
#define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit"
#define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit"
#define DUK_STR_C_CALLSTACK_LIMIT "C call stack depth limit"
@@ -3114,20 +3112,20 @@ typedef duk_uint32_t duk_instr_t;
/* Opcodes. */
#define DUK_OP_LDREG 0
#define DUK_OP_STREG 1
-#define DUK_OP_LDCONST 2
-#define DUK_OP_LDINT 3
-#define DUK_OP_LDINTX 4
-#define DUK_OP_LDTHIS 5
-#define DUK_OP_LDUNDEF 6
-#define DUK_OP_LDNULL 7
-#define DUK_OP_LDTRUE 8
-#define DUK_OP_LDFALSE 9
-#define DUK_OP_BNOT 10
-#define DUK_OP_LNOT 11
-#define DUK_OP_UNM 12
-#define DUK_OP_UNP 13
-#define DUK_OP_TYPEOF 14
-#define DUK_OP_TYPEOFID 15
+#define DUK_OP_JUMP 2
+#define DUK_OP_LDCONST 3
+#define DUK_OP_LDINT 4
+#define DUK_OP_LDINTX 5
+#define DUK_OP_LDTHIS 6
+#define DUK_OP_LDUNDEF 7
+#define DUK_OP_LDNULL 8
+#define DUK_OP_LDTRUE 9
+#define DUK_OP_LDFALSE 10
+#define DUK_OP_GETVAR 11
+#define DUK_OP_BNOT 12
+#define DUK_OP_LNOT 13
+#define DUK_OP_UNM 14
+#define DUK_OP_UNP 15
#define DUK_OP_EQ 16
#define DUK_OP_EQ_RR 16
#define DUK_OP_EQ_CR 17
@@ -3297,67 +3295,68 @@ typedef duk_uint32_t duk_instr_t;
#define DUK_OP_REGEXP_CR 149
#define DUK_OP_REGEXP_RC 150
#define DUK_OP_REGEXP_CC 151
-#define DUK_OP_CSVAR 152
-#define DUK_OP_CSVAR_RR 152
-#define DUK_OP_CSVAR_CR 153
-#define DUK_OP_CSVAR_RC 154
-#define DUK_OP_CSVAR_CC 155
-#define DUK_OP_CLOSURE 156
-#define DUK_OP_GETVAR 157
-#define DUK_OP_PUTVAR 158
-#define DUK_OP_DELVAR 159
-#define DUK_OP_JUMP 160
-#define DUK_OP_RETREG 161
-#define DUK_OP_RETUNDEF 162
-#define DUK_OP_RETCONST 163
-#define DUK_OP_RETCONSTN 164 /* return const without incref (e.g. number) */
-#define DUK_OP_LABEL 165
-#define DUK_OP_ENDLABEL 166
-#define DUK_OP_BREAK 167
-#define DUK_OP_CONTINUE 168
-#define DUK_OP_TRYCATCH 169
-#define DUK_OP_ENDTRY 170
-#define DUK_OP_ENDCATCH 171
-#define DUK_OP_ENDFIN 172
-#define DUK_OP_THROW 173
-#define DUK_OP_CSREG 174
-#define DUK_OP_EVALCALL 175
-#define DUK_OP_CALL 176 /* must be even */
-#define DUK_OP_TAILCALL 177 /* must be odd */
-#define DUK_OP_NEW 178
-#define DUK_OP_NEWOBJ 179
-#define DUK_OP_NEWARR 180
-#define DUK_OP_MPUTOBJ 181
-#define DUK_OP_MPUTOBJI 182
-#define DUK_OP_INITSET 183
-#define DUK_OP_INITGET 184
-#define DUK_OP_MPUTARR 185
-#define DUK_OP_MPUTARRI 186
-#define DUK_OP_SETALEN 187
-#define DUK_OP_INITENUM 188
-#define DUK_OP_NEXTENUM 189
-#define DUK_OP_INVLHS 190
-#define DUK_OP_DEBUGGER 191
-#define DUK_OP_NOP 192
-#define DUK_OP_INVALID 193
-#define DUK_OP_UNUSED194 194
-#define DUK_OP_UNUSED195 195
-#define DUK_OP_UNUSED196 196
-#define DUK_OP_UNUSED197 197
-#define DUK_OP_UNUSED198 198
-#define DUK_OP_UNUSED199 199
-#define DUK_OP_UNUSED200 200
-#define DUK_OP_UNUSED201 201
-#define DUK_OP_UNUSED202 202
-#define DUK_OP_UNUSED203 203
-#define DUK_OP_UNUSED204 204
-#define DUK_OP_UNUSED205 205
-#define DUK_OP_UNUSED206 206
+#define DUK_OP_CLOSURE 152
+#define DUK_OP_TYPEOF 153
+#define DUK_OP_TYPEOFID 154
+#define DUK_OP_PUTVAR 155
+#define DUK_OP_DELVAR 156
+#define DUK_OP_RETREG 157
+#define DUK_OP_RETUNDEF 158
+#define DUK_OP_RETCONST 159
+#define DUK_OP_RETCONSTN 160 /* return const without incref (e.g. number) */
+#define DUK_OP_LABEL 161
+#define DUK_OP_ENDLABEL 162
+#define DUK_OP_BREAK 163
+#define DUK_OP_CONTINUE 164
+#define DUK_OP_TRYCATCH 165
+#define DUK_OP_ENDTRY 166
+#define DUK_OP_ENDCATCH 167
+#define DUK_OP_ENDFIN 168
+#define DUK_OP_THROW 169
+#define DUK_OP_INVLHS 170
+#define DUK_OP_CSREG 171
+#define DUK_OP_CSVAR 172
+#define DUK_OP_CSVAR_RR 172
+#define DUK_OP_CSVAR_CR 173
+#define DUK_OP_CSVAR_RC 174
+#define DUK_OP_CSVAR_CC 175
+#define DUK_OP_CALL0 176 /* DUK_OP_CALL0 & 0x0F must be zero. */
+#define DUK_OP_CALL1 177
+#define DUK_OP_CALL2 178
+#define DUK_OP_CALL3 179
+#define DUK_OP_CALL4 180
+#define DUK_OP_CALL5 181
+#define DUK_OP_CALL6 182
+#define DUK_OP_CALL7 183
+#define DUK_OP_CALL8 184
+#define DUK_OP_CALL9 185
+#define DUK_OP_CALL10 186
+#define DUK_OP_CALL11 187
+#define DUK_OP_CALL12 188
+#define DUK_OP_CALL13 189
+#define DUK_OP_CALL14 190
+#define DUK_OP_CALL15 191
+#define DUK_OP_NEWOBJ 192
+#define DUK_OP_NEWARR 193
+#define DUK_OP_MPUTOBJ 194
+#define DUK_OP_MPUTOBJI 195
+#define DUK_OP_INITSET 196
+#define DUK_OP_INITGET 197
+#define DUK_OP_MPUTARR 198
+#define DUK_OP_MPUTARRI 199
+#define DUK_OP_SETALEN 200
+#define DUK_OP_INITENUM 201
+#define DUK_OP_NEXTENUM 202
+#define DUK_OP_NEWTARGET 203
+#define DUK_OP_DEBUGGER 204
+#define DUK_OP_NOP 205
+#define DUK_OP_INVALID 206
#define DUK_OP_UNUSED207 207
-#define DUK_OP_UNUSED208 208
-#define DUK_OP_UNUSED209 209
-#define DUK_OP_UNUSED210 210
-#define DUK_OP_UNUSED211 211
+#define DUK_OP_GETPROPC 208
+#define DUK_OP_GETPROPC_RR 208
+#define DUK_OP_GETPROPC_CR 209
+#define DUK_OP_GETPROPC_RC 210
+#define DUK_OP_GETPROPC_CC 211
#define DUK_OP_UNUSED212 212
#define DUK_OP_UNUSED213 213
#define DUK_OP_UNUSED214 214
@@ -3407,14 +3406,24 @@ typedef duk_uint32_t duk_instr_t;
/* XXX: Allocate flags from opcode field? Would take 16 opcode slots
* but avoids shuffling in more cases. Maybe not worth it.
*/
-/* DUK_OP_TRYCATCH flags in A */
-#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0)
-#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1)
-#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2)
-#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3)
+/* DUK_OP_TRYCATCH flags in A. */
+#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1U << 0)
+#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1U << 1)
+#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1U << 2)
+#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1U << 3)
+
+/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags
+ * (DUK_PROPDESC_FLAG_XXX).
+ */
+#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1U << 4) /* function declaration */
-/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
-#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 4) /* function declaration */
+/* DUK_OP_CALLn flags, part of opcode field. Three lowest bits must match
+ * DUK_CALL_FLAG_xxx directly.
+ */
+#define DUK_BC_CALL_FLAG_TAILCALL (1U << 0)
+#define DUK_BC_CALL_FLAG_CONSTRUCT (1U << 1)
+#define DUK_BC_CALL_FLAG_CALLED_AS_EVAL (1U << 2)
+#define DUK_BC_CALL_FLAG_INDIRECT (1U << 3)
/* Misc constants and helper macros. */
#define DUK_BC_LDINT_BIAS (1L << 15)
@@ -3597,6 +3606,8 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
#define DUK_TOK_MAXVAL 101 /* inclusive */
+#define DUK_TOK_INVALID DUK_SMALL_UINT_MAX
+
/* Convert heap string index to a token (reserved words) */
#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
@@ -3775,8 +3786,8 @@ typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepo
* stale values otherwise.
*/
struct duk_token {
- duk_small_int_t t; /* token type (with reserved word identification) */
- duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
+ duk_small_uint_t t; /* token type (with reserved word identification) */
+ duk_small_uint_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
duk_double_t num; /* numeric value of token */
duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
@@ -3791,11 +3802,11 @@ struct duk_token {
/* A regexp token value. */
struct duk_re_token {
- duk_small_int_t t; /* token type */
- duk_small_int_t greedy;
- duk_uint_fast32_t num; /* numeric value (character, count) */
- duk_uint_fast32_t qmin;
- duk_uint_fast32_t qmax;
+ duk_small_uint_t t; /* token type */
+ duk_small_uint_t greedy;
+ duk_uint32_t num; /* numeric value (character, count) */
+ duk_uint32_t qmin;
+ duk_uint32_t qmax;
};
/* A structure for 'snapshotting' a point for rewinding */
@@ -3898,13 +3909,12 @@ DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_
* Chosen so that when a regconst is cast to duk_int32_t, all consts are
* negative values.
*/
-#define DUK_REGCONST_CONST_MARKER 0x80000000UL
-
-/* type to represent a reg/const reference during compilation */
-typedef duk_uint32_t duk_regconst_t;
+#define DUK_REGCONST_CONST_MARKER DUK_INT32_MIN /* = -0x80000000 */
-/* type to represent a straight register reference, with <0 indicating none */
-typedef duk_int32_t duk_reg_t;
+/* Type to represent a reg/const reference during compilation, with <0
+ * indicating a constant. Some call sites also use -1 to indicate 'none'.
+ */
+typedef duk_int32_t duk_regconst_t;
typedef struct {
duk_small_uint_t t; /* DUK_ISPEC_XXX */
@@ -3944,8 +3954,8 @@ struct duk_compiler_instr {
* Compiler state
*/
-#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0)
-#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1)
+#define DUK_LABEL_FLAG_ALLOW_BREAK (1U << 0)
+#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1U << 1)
#define DUK_DECL_TYPE_VAR 0
#define DUK_DECL_TYPE_FUNC 1
@@ -4003,14 +4013,14 @@ struct duk_compiler_func {
duk_idx_t varmap_idx;
/* Temp reg handling. */
- duk_reg_t temp_first; /* first register that is a temporary (below: variables) */
- duk_reg_t temp_next; /* next temporary register to allocate */
- duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
+ duk_regconst_t temp_first; /* first register that is a temporary (below: variables) */
+ duk_regconst_t temp_next; /* next temporary register to allocate */
+ duk_regconst_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
/* Shuffle registers if large number of regs/consts. */
- duk_reg_t shuffle1;
- duk_reg_t shuffle2;
- duk_reg_t shuffle3;
+ duk_regconst_t shuffle1;
+ duk_regconst_t shuffle2;
+ duk_regconst_t shuffle3;
/* Stats for current expression being parsed. */
duk_int_t nud_count;
@@ -4026,7 +4036,7 @@ struct duk_compiler_func {
duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
duk_int_t fnum_next; /* inner function numbering */
duk_int_t num_formals; /* number of formal arguments */
- duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
+ duk_regconst_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */
duk_int_t max_line;
@@ -4126,9 +4136,9 @@ DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_b
#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
/* flags */
-#define DUK_RE_FLAG_GLOBAL (1 << 0)
-#define DUK_RE_FLAG_IGNORE_CASE (1 << 1)
-#define DUK_RE_FLAG_MULTILINE (1 << 2)
+#define DUK_RE_FLAG_GLOBAL (1U << 0)
+#define DUK_RE_FLAG_IGNORE_CASE (1U << 1)
+#define DUK_RE_FLAG_MULTILINE (1U << 2)
struct duk_re_matcher_ctx {
duk_hthread *thr;
@@ -5142,10 +5152,37 @@ struct duk_heaphdr_string {
#endif /* DUK_USE_REFERENCE_COUNTING */
+/*
+ * Some convenience macros that don't have optimized implementations now.
+ */
+
+#define DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr,tv_dst,tv_src) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_tval *duk__dst = (tv_dst); \
+ duk_tval *duk__src = (tv_src); \
+ DUK_UNREF(duk__thr); \
+ DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
+ DUK_TVAL_SET_TVAL(duk__dst, duk__src); \
+ DUK_TVAL_INCREF(thr, duk__dst); \
+ } while (0)
+
+#define DUK_TVAL_SET_U32_UPDREF_NORZ(thr,tv_dst,val) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_tval *duk__dst = (tv_dst); \
+ duk_uint32_t duk__val = (duk_uint32_t) (val); \
+ DUK_UNREF(duk__thr); \
+ DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
+ DUK_TVAL_SET_U32(duk__dst, duk__val); \
+ } while (0)
+
+/*
+ * Prototypes
+ */
+
#if defined(DUK_USE_REFERENCE_COUNTING)
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr);
-DUK_INTERNAL_DECL DUK_INLINE void duk_refzero_check_fast(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr);
#endif
DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr);
DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h);
@@ -5186,6 +5223,8 @@ DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h)
#if !defined(DUK_API_INTERNAL_H_INCLUDED)
#define DUK_API_INTERNAL_H_INCLUDED
+#define DUK_INTERNAL_SYMBOL(x) ("\x82" x)
+
/* duk_push_sprintf constants */
#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
@@ -5195,186 +5234,197 @@ DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h)
*/
#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
-/* Valstack resize flags */
-#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0)
-#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1)
-#define DUK_VSRESIZE_FLAG_THROW (1 << 2)
-
/* Current convention is to use duk_size_t for value stack sizes and global indices,
* and duk_idx_t for local frame indices.
*/
-DUK_INTERNAL_DECL
-duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes);
+DUK_INTERNAL_DECL duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes);
+DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug);
+
+DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count);
+
+DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count);
-DUK_INTERNAL_DECL void duk_dup_0(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_dup_1(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_dup_2(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start);
+
+DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr);
/* duk_dup_m1() would be same as duk_dup_top() */
-DUK_INTERNAL_DECL void duk_dup_m2(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_dup_m3(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_dup_m4(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_remove_m2(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv);
DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv);
#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx);
#endif
-DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_context *ctx, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
+DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv);
/* Push the current 'this' binding; throw TypeError if binding is not object
* coercible (CheckObjectCoercible).
*/
-DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
-DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
-DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);
+DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr);
-DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_context *ctx, duk_uint_t i);
+DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i);
/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
* make sure there's an active callstack entry. Note that the returned pointer
* is unstable with regards to side effects.
*/
-DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
+DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr);
/* XXX: add fastint support? */
-#define duk_push_u64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
-#define duk_push_i64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
+#define duk_push_u64(thr,val) \
+ duk_push_number((thr), (duk_double_t) (val))
+#define duk_push_i64(thr,val) \
+ duk_push_number((thr), (duk_double_t) (val))
/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
-#define duk_push_u32(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_i32(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
+#define duk_push_u32(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val))
+#define duk_push_i32(thr,val) \
+ duk_push_int((thr), (duk_int_t) (val))
/* sometimes stack and array indices need to go on the stack */
-#define duk_push_idx(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
-#define duk_push_uarridx(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_size_t(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
-
-DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_context *ctx, duk_idx_t idx);
-
-DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx);
-
-DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer);
-
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum);
-
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask);
-#define duk_require_hobject_promote_lfunc(ctx,idx) \
- duk_require_hobject_promote_mask((ctx), (idx), DUK_TYPE_MASK_LIGHTFUNC)
-#define duk_get_hobject_promote_lfunc(ctx,idx) \
- duk_get_hobject_promote_mask((ctx), (idx), DUK_TYPE_MASK_LIGHTFUNC)
+#define duk_push_idx(thr,val) \
+ duk_push_int((thr), (duk_int_t) (val))
+#define duk_push_uarridx(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val))
+#define duk_push_size_t(thr,val) \
+ duk_push_uint((thr), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
+
+DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv);
+
+DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer);
+
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
+
+DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
+#define duk_require_hobject_promote_lfunc(thr,idx) \
+ duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
+#define duk_get_hobject_promote_lfunc(thr,idx) \
+ duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
#if 0 /*unused*/
-DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx);
+DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx);
#endif
-DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_context *ctx, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_context *ctx, duk_tval *tv);
+DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_context *ctx);
-DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_context *ctx, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_context *ctx, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_context *ctx);
-DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr);
#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 idx);
+DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx);
#endif
-DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_context *ctx, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
-DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
+DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
+DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
+DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t idx);
-#endif
-DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_context *ctx, duk_idx_t idx);
-
-DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len);
-DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx);
-
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum);
-
-DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h);
-DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_uint_t stridx);
-DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h);
-DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
-#define duk_push_hthread(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-#define duk_push_hnatfunc(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx);
-DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
-DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
-DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
-DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
+DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx);
+#endif
+DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len);
+DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx);
+
+DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
+
+DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx);
+DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h);
+DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h);
+#define duk_push_hthread(thr,h) \
+ duk_push_hobject((thr), (duk_hobject *) (h))
+#define duk_push_hnatfunc(thr,h) \
+ duk_push_hobject((thr), (duk_hobject *) (h))
+DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
+DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
+DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
+DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with
* duk_push_hobject() etc which don't create a new value.
*/
-DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_context *ctx);
-DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_context *ctx, duk_uint32_t size);
+DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size);
+DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size);
-DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz);
-DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags);
-DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz);
+DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags);
+DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv);
+#if 0 /* not used yet */
+DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h);
+#endif
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
+DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
#endif
-DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_context *ctx, duk_size_t len);
-DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_context *ctx, duk_size_t len);
+DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len);
+DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len);
-DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_context *ctx, duk_tval *tv);
+DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv);
/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short
* enough to be packed into a single 32-bit integer argument. Argument limits
@@ -5383,112 +5433,135 @@ DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_context *c
* arguments and such call sites are also easiest to verify to be correct.
*/
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
-#define duk_get_prop_stridx_short(ctx,obj_idx,stridx) \
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_get_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
- duk_get_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
+ duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
-#define duk_put_prop_stridx_short(ctx,obj_idx,stridx) \
+DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */
+DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_put_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
- duk_put_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+ duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
-DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
#if 0 /* Too few call sites to be useful. */
-DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
-#define duk_del_prop_stridx_short(ctx,obj_idx,stridx) \
+DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
- duk_del_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+ duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
#endif
-#define duk_del_prop_stridx_short(ctx,obj_idx,stridx) \
- duk_del_prop_stridx((ctx), (obj_idx), (stridx))
+#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
+ duk_del_prop_stridx((thr), (obj_idx), (stridx))
-DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
#if 0 /* Too few call sites to be useful. */
-DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
-#define duk_has_prop_stridx_short(ctx,obj_idx,stridx) \
+DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
- duk_has_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
+ duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
#endif
-#define duk_has_prop_stridx_short(ctx,obj_idx,stridx) \
- duk_has_prop_stridx((ctx), (obj_idx), (stridx))
+#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
+ duk_has_prop_stridx((thr), (obj_idx), (stridx))
-DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */
+DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */
+DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */
/* XXX: Because stridx and desc_flags have a limited range, this call could
* always pack stridx and desc_flags into a single argument.
*/
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
-#define duk_xdef_prop_stridx_short(ctx,obj_idx,stridx,desc_flags) \
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
+#define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \
(DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \
DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \
- duk_xdef_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
+ duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
-#define duk_xdef_prop_wec(ctx,obj_idx) \
- duk_xdef_prop((ctx), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_index_wec(ctx,obj_idx,arr_idx) \
- duk_xdef_prop_index((ctx), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_stridx_wec(ctx,obj_idx,stridx) \
- duk_xdef_prop_stridx((ctx), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_stridx_short_wec(ctx,obj_idx,stridx) \
- duk_xdef_prop_stridx_short((ctx), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_wec(thr,obj_idx) \
+ duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \
+ duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \
+ duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
+#define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \
+ duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
+#if 0 /*unused*/
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
+#endif
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
-DUK_INTERNAL_DECL void duk_pack(duk_context *ctx, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx);
#if 0
-DUK_INTERNAL_DECL void duk_unpack(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr);
#endif
-DUK_INTERNAL_DECL void duk_require_constructor_call(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_require_constructable(duk_context *ctx, duk_idx_t idx);
-DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_context *ctx, duk_hstring *h);
+DUK_INTERNAL_DECL void duk_require_constructor_call(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h);
+
+DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_context *ctx);
+DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top);
+DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr);
-DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top);
-DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count);
-DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count);
-DUK_INTERNAL_DECL void duk_pop_unsafe(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count);
+DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx);
+DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr);
+
+DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze);
+
+DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
+
+DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr);
+
+DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
/* Raw internal valstack access macros: access is unsafe so call site
* must have a guarantee that the index is valid. When that is the case,
* using these macro results in faster and smaller code than duk_get_tval().
* Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
*/
-#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
-#define DUK_GET_TVAL_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
-#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
-#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
+#define DUK_ASSERT_VALID_NEGIDX(thr,idx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
+#define DUK_ASSERT_VALID_POSIDX(thr,idx) \
+ (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
+#define DUK_GET_TVAL_NEGIDX(thr,idx) \
+ (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx))
+#define DUK_GET_TVAL_POSIDX(thr,idx) \
+ (DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx))
+#define DUK_GET_HOBJECT_NEGIDX(thr,idx) \
+ (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx)))
+#define DUK_GET_HOBJECT_POSIDX(thr,idx) \
+ (DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx)))
#define DUK_GET_THIS_TVAL_PTR(thr) \
(DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
(thr)->valstack_bottom - 1)
+DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
+
#endif /* DUK_API_INTERNAL_H_INCLUDED */
/* #include duk_hstring.h */
/*
@@ -5628,7 +5701,9 @@ DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx);
#define DUK_HSTRING_GET_DATA_END(x) \
(DUK_HSTRING_GET_DATA((x)) + (x)->blen)
-/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
+/* Marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest
+ * valid).
+ */
#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
#if defined(DUK_USE_HSTRING_ARRIDX)
@@ -5646,6 +5721,12 @@ DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx);
(duk_js_to_arrayindex_hstring_fast((h)))
#endif
+/* XXX: these actually fit into duk_hstring */
+#define DUK_SYMBOL_TYPE_HIDDEN 0
+#define DUK_SYMBOL_TYPE_GLOBAL 1
+#define DUK_SYMBOL_TYPE_LOCAL 2
+#define DUK_SYMBOL_TYPE_WELLKNOWN 3
+
/*
* Misc
*/
@@ -5714,7 +5795,11 @@ struct duk_hstring_external {
*/
DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware);
+DUK_INTERNAL_DECL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr);
DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
+#if !defined(DUK_USE_HSTRING_LAZY_CLEN)
+DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h);
+#endif
#endif /* DUK_HSTRING_H_INCLUDED */
/* #include duk_hobject.h */
@@ -5761,7 +5846,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
*/
#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
-#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */
+#define DUK_HOBJECT_FLAG_CALLABLE DUK_HEAPHDR_USER_FLAG(2) /* object is callable */
+#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(3) /* object established using Function.prototype.bind() */
#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */
#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */
#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */
@@ -5772,12 +5858,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */
#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
-#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable finalizer property */
+#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable (own) finalizer property */
#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
-#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */
-#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
+#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */
+#define DUK_HOBJECT_FLAG_SPECIAL_CALL DUK_HEAPHDR_USER_FLAG(19) /* special casing in call behavior, for .call(), .apply(), etc. */
#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
#define DUK_HOBJECT_FLAG_CLASS_BITS 5
@@ -5884,8 +5970,17 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#else
+#define DUK_HOBJECT_IS_BUFOBJ(h) 0
+#endif
#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD)
+#if defined(DUK_USE_ES6_PROXY)
+#define DUK_HOBJECT_IS_PROXY(h) DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h))
+#else
+#define DUK_HOBJECT_IS_PROXY(h) 0
+#endif
#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
DUK_HOBJECT_FLAG_COMPFUNC | \
@@ -5896,16 +5991,12 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_HOBJECT_FLAG_COMPFUNC | \
DUK_HOBJECT_FLAG_NATFUNC)
-#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_BOUNDFUNC | \
- DUK_HOBJECT_FLAG_COMPFUNC | \
- DUK_HOBJECT_FLAG_NATFUNC)
+#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HOBJECT_HAS_CALLABLE((h))
/* Object has any exotic behavior(s). */
#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
DUK_HOBJECT_FLAG_BUFOBJ | \
DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
@@ -5913,16 +6004,20 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
/* Object has any virtual properties (not counting Proxy behavior). */
#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
DUK_HOBJECT_FLAG_BUFOBJ)
#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS)
#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
+#define DUK_HOBJECT_HAS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#else
+#define DUK_HOBJECT_HAS_BUFOBJ(h) 0
+#endif
#define DUK_HOBJECT_HAS_FASTREFS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
@@ -5934,15 +6029,22 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#else
+#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) 0
+#endif
+#define DUK_HOBJECT_HAS_SPECIAL_CALL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
+#define DUK_HOBJECT_SET_CALLABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#endif
#define DUK_HOBJECT_SET_FASTREFS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
@@ -5954,15 +6056,20 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#endif
+#define DUK_HOBJECT_SET_SPECIAL_CALL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
+#define DUK_HOBJECT_CLEAR_CALLABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
+#endif
#define DUK_HOBJECT_CLEAR_FASTREFS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
@@ -5974,25 +6081,29 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
+#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
+#endif
+#define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond
- * duk_hobject base header.
+ * duk_hobject base header. This is used just for asserts so doesn't need to
+ * be optimized.
*/
#define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \
(DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \
- DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)))
+ DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \
+ DUK_HOBJECT_IS_BOUNDFUNC((h)))
#define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h)))
/* Flags used for property attributes in duk_propdesc and packed flags.
* Must fit into 8 bits.
*/
-#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
-#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
+#define DUK_PROPDESC_FLAG_WRITABLE (1U << 0) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_ENUMERABLE (1U << 1) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_CONFIGURABLE (1U << 2) /* E5 Section 8.6.1 */
+#define DUK_PROPDESC_FLAG_ACCESSOR (1U << 3) /* accessor */
+#define DUK_PROPDESC_FLAG_VIRTUAL (1U << 4) /* property is virtual: used in duk_propdesc, never stored
* (used by e.g. buffer virtual properties)
*/
#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
@@ -6003,7 +6114,7 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
/* Additional flags which are passed in the same flags argument as property
* flags but are not stored in object properties.
*/
-#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */
+#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1U << 4) /* internal define property: skip write silently if exists */
/* Convenience defines for property attributes. */
#define DUK_PROPDESC_FLAGS_NONE 0
@@ -6018,8 +6129,8 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
DUK_PROPDESC_FLAG_CONFIGURABLE)
/* Flags for duk_hobject_get_own_propdesc() and variants. */
-#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */
-#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */
+#define DUK_GETDESC_FLAG_PUSH_VALUE (1U << 0) /* push value to stack */
+#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1U << 1) /* don't throw for prototype loop */
/*
* Macro for object validity check
@@ -6328,9 +6439,6 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
*/
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
-/* Maximum traversal depth for "bound function" chains. */
-#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L
-
/*
* Ecmascript [[Class]]
*/
@@ -6362,9 +6470,22 @@ DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
} while (0)
#endif
-/* note: this updates refcounts */
+/* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
+/* Set initial prototype, assume NULL previous prototype, INCREF new value,
+ * tolerate NULL.
+ */
+#define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \
+ duk_hthread *duk__thr = (thr); \
+ duk_hobject *duk__obj = (h); \
+ duk_hobject *duk__proto = (proto); \
+ DUK_UNREF(duk__thr); \
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \
+ DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \
+ DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \
+ } while (0)
+
/*
* Finalizer check
*/
@@ -6560,6 +6681,7 @@ DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t ho
DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
#endif
@@ -6567,6 +6689,7 @@ DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_u
DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
+DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
/* resize */
DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
@@ -6575,11 +6698,19 @@ DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
duk_uint32_t new_a_size,
duk_uint32_t new_h_size,
duk_bool_t abandon_array);
+DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size);
+#if 0 /*unused*/
+DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_a_size);
+#endif
/* low-level property functions */
-DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
-DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs);
+DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
@@ -6596,8 +6727,8 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
/* internal property functions */
-#define DUK_DELPROP_FLAG_THROW (1 << 0)
-#define DUK_DELPROP_FLAG_FORCE (1 << 1)
+#define DUK_DELPROP_FLAG_THROW (1U << 0)
+#define DUK_DELPROP_FLAG_FORCE (1U << 1)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
@@ -6610,28 +6741,26 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj
#endif
/* helpers for defineProperty() and defineProperties() */
-DUK_INTERNAL_DECL
-void duk_hobject_prepare_property_descriptor(duk_context *ctx,
- duk_idx_t idx_in,
- duk_uint_t *out_defprop_flags,
- duk_idx_t *out_idx_value,
- duk_hobject **out_getter,
- duk_hobject **out_setter);
-DUK_INTERNAL_DECL
-duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
- duk_uint_t defprop_flags,
- duk_hobject *obj,
- duk_hstring *key,
- duk_idx_t idx_value,
- duk_hobject *get,
- duk_hobject *set,
- duk_bool_t throw_flag);
+DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
+ duk_idx_t idx_in,
+ duk_uint_t *out_defprop_flags,
+ duk_idx_t *out_idx_value,
+ duk_hobject **out_getter,
+ duk_hobject **out_setter);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
+ duk_uint_t defprop_flags,
+ duk_hobject *obj,
+ duk_hstring *key,
+ duk_idx_t idx_value,
+ duk_hobject *get,
+ duk_hobject *set,
+ duk_bool_t throw_flag);
/* Object built-in methods */
-DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_context *ctx, duk_idx_t obj_idx);
+DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx);
DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags);
/* internal properties */
DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
@@ -6642,14 +6771,14 @@ DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *
/* ES2015 proxy */
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
+DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj);
#endif
/* enumeration */
-DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value);
+DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags);
+DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags);
+DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value);
/* macros */
DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
@@ -6657,7 +6786,7 @@ DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_ho
/* pc2line */
#if defined(DUK_USE_PC2LINE)
DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc);
+DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc);
#endif
/* misc */
@@ -6667,8 +6796,8 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *t
/* These declarations are needed when related built-in is disabled and
* genbuiltins.py won't automatically emit the declerations.
*/
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr);
#endif
#endif /* DUK_HOBJECT_H_INCLUDED */
@@ -6802,6 +6931,13 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \
((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
+/*
+ * Validity assert
+ */
+
+#define DUK_ASSERT_HCOMPFUNC_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ } while (0)
/*
* Main struct
@@ -6964,11 +7100,52 @@ struct duk_hnatfunc {
* versa.
*
* Note: cannot place nargs/magic into the heaphdr flags, because
- * duk_hobject takes almost all flags already (and needs the spare).
+ * duk_hobject takes almost all flags already.
*/
};
#endif /* DUK_HNATFUNC_H_INCLUDED */
+/* #include duk_hboundfunc.h */
+/*
+ * Bound function representation.
+ */
+
+#if !defined(DUK_HBOUNDFUNC_H_INCLUDED)
+#define DUK_HBOUNDFUNC_H_INCLUDED
+
+/* Artificial limit for args length. Ensures arithmetic won't overflow
+ * 32 bits when combining bound functions.
+ */
+#define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL
+
+#define DUK_ASSERT_HBOUNDFUNC_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) (h))); \
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&(h)->target) || \
+ (DUK_TVAL_IS_OBJECT(&(h)->target) && \
+ DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&(h)->target)))); \
+ DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&(h)->this_binding)); \
+ DUK_ASSERT((h)->nargs == 0 || (h)->args != NULL); \
+ } while (0)
+
+struct duk_hboundfunc {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Final target function, stored as duk_tval so that lightfunc can be
+ * represented too.
+ */
+ duk_tval target;
+
+ /* This binding. */
+ duk_tval this_binding;
+
+ /* Arguments to prepend. */
+ duk_tval *args; /* Separate allocation. */
+ duk_idx_t nargs;
+};
+
+#endif /* DUK_HBOUNDFUNC_H_INCLUDED */
/* #include duk_hbufobj.h */
/*
* Heap Buffer object representation. Used for all Buffer variants.
@@ -7106,9 +7283,9 @@ struct duk_hbufobj {
DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len);
DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf);
-DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
-DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
-DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx);
+DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
+DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx);
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#endif /* DUK_HBUFOBJ_H_INCLUDED */
@@ -7116,8 +7293,9 @@ DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx
/*
* Heap thread object representation.
*
- * duk_hthread is also the 'context' (duk_context) for exposed APIs
- * which mostly operate on the topmost frame of the value stack.
+ * duk_hthread is also the 'context' for public API functions via a
+ * different typedef. Most API calls operate on the topmost frame
+ * of the value stack only.
*/
#if !defined(DUK_HTHREAD_H_INCLUDED)
@@ -7127,61 +7305,46 @@ DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx
* Stack constants
*/
-#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */
-#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */
-#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */
-#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
-#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry,
- * always added to user-defined 'extra' for e.g. the
- * duk_check_stack() call.
- */
-#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
- /* number of elements guaranteed to be user accessible
- * (in addition to call arguments) on Duktape/C function entry.
- */
+/* Initial valstack size, roughly 0.7kiB. */
+#define DUK_VALSTACK_INITIAL_SIZE 96U
-/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
- * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
- * requirements.
+/* Internal extra elements assumed on function entry, always added to
+ * user-defined 'extra' for e.g. the duk_check_stack() call.
*/
+#define DUK_VALSTACK_INTERNAL_EXTRA 32U
-#define DUK_VALSTACK_DEFAULT_MAX 1000000L
-
-#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */
-#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_INITIAL_SIZE 8
-#define DUK_CALLSTACK_DEFAULT_MAX 10000L
-
-#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */
-#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_INITIAL_SIZE 4
-#define DUK_CATCHSTACK_DEFAULT_MAX 10000L
+/* Number of elements guaranteed to be user accessible (in addition to call
+ * arguments) on Duktape/C function entry. This is the major public API
+ * commitment.
+ */
+#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
/*
* Activation defines
*/
-#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */
-#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */
-#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */
-#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */
-#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */
-#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */
+#define DUK_ACT_FLAG_STRICT (1U << 0) /* function executes in strict mode */
+#define DUK_ACT_FLAG_TAILCALLED (1U << 1) /* activation has tail called one or more times */
+#define DUK_ACT_FLAG_CONSTRUCT (1U << 2) /* function executes as a constructor (called via "new") */
+#define DUK_ACT_FLAG_PREVENT_YIELD (1U << 3) /* activation prevents yield (native call or "new") */
+#define DUK_ACT_FLAG_DIRECT_EVAL (1U << 4) /* activation is a direct eval call */
+#define DUK_ACT_FLAG_CONSTRUCT_PROXY (1U << 5) /* activation is for Proxy 'construct' call, special return value handling */
+#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1U << 6) /* activation has active breakpoint(s) */
-#define DUK_ACT_GET_FUNC(act) ((act)->func)
+#define DUK_ACT_GET_FUNC(act) ((act)->func)
/*
* Flags for __FILE__ / __LINE__ registered into tracedata
*/
-#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
+#define DUK_TB_FLAG_NOBLAME_FILELINE (1U << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
/*
* Catcher defines
*/
+/* XXX: remove catcher type entirely */
+
/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
#define DUK_CAT_TYPE_MASK 0x0000000fUL
#define DUK_CAT_TYPE_BITS 4
@@ -7189,10 +7352,10 @@ DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx
#define DUK_CAT_LABEL_BITS 24
#define DUK_CAT_LABEL_SHIFT 8
-#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */
-#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */
-#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */
-#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */
+#define DUK_CAT_FLAG_CATCH_ENABLED (1U << 4) /* catch part will catch */
+#define DUK_CAT_FLAG_FINALLY_ENABLED (1U << 5) /* finally part will catch */
+#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1U << 6) /* request to create catch binding */
+#define DUK_CAT_FLAG_LEXENV_ACTIVE (1U << 7) /* catch or with binding is currently active */
#define DUK_CAT_TYPE_UNKNOWN 0
#define DUK_CAT_TYPE_TCF 1
@@ -7273,25 +7436,39 @@ DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx
* diagnose behavior so it's worth checking even when the check is not 100%.
*/
-#if defined(DUK_USE_PREFER_SIZE)
-#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/
-#else
-#define DUK_ASSERT_CTX_VSSIZE(ctx) \
- DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \
- ((duk_hthread *) (ctx))->valstack_size)
-#endif
-#define DUK_ASSERT_CTX_VALID(ctx) do { \
- DUK_ASSERT((ctx) != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \
- DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \
- DUK_ASSERT_CTX_VSSIZE((ctx)); \
+/* Assertions for internals. */
+#define DUK_ASSERT_HTHREAD_VALID(thr) do { \
+ DUK_ASSERT((thr) != NULL); \
+ DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (thr)) == DUK_HTYPE_OBJECT); \
+ DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (thr))); \
+ DUK_ASSERT((thr)->unused1 == 0); \
+ DUK_ASSERT((thr)->unused2 == 0); \
+ } while (0)
+
+/* Assertions for public API calls; a bit stronger. */
+#define DUK_ASSERT_CTX_VALID(thr) do { \
+ DUK_ASSERT((thr) != NULL); \
+ DUK_ASSERT_HTHREAD_VALID((thr)); \
+ DUK_ASSERT((thr)->valstack != NULL); \
+ DUK_ASSERT((thr)->valstack_bottom != NULL); \
+ DUK_ASSERT((thr)->valstack_top != NULL); \
+ DUK_ASSERT((thr)->valstack_end != NULL); \
+ DUK_ASSERT((thr)->valstack_alloc_end != NULL); \
+ DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_end >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_top >= (thr)->valstack); \
+ DUK_ASSERT((thr)->valstack_top >= (thr)->valstack_bottom); \
+ DUK_ASSERT((thr)->valstack_end >= (thr)->valstack_top); \
+ DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack_end); \
+ } while (0)
+
+/* Assertions for API call entry specifically. Checks 'ctx' but also may
+ * check internal state (e.g. not in a debugger transport callback).
+ */
+#define DUK_ASSERT_API_ENTRY(thr) do { \
+ DUK_ASSERT_CTX_VALID((thr)); \
+ DUK_ASSERT((thr)->heap != NULL); \
+ DUK_ASSERT((thr)->heap->dbg_calling_transport == 0); \
} while (0)
/*
@@ -7318,16 +7495,15 @@ DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx
* Struct defines
*/
-/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function
- * or a macro. This would make the activation 32 bytes long on 32-bit platforms again.
- */
-
-/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */
+/* Fields are ordered for alignment/packing. */
struct duk_activation {
duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
+ duk_activation *parent; /* previous (parent) activation (or NULL if none) */
duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
+ duk_catcher *cat; /* current catcher (or NULL) */
+
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
/* Previous value of 'func' caller, restored when unwound. Only in use
* when 'func' is non-strict.
@@ -7336,52 +7512,61 @@ struct duk_activation {
#endif
duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_uint32_t prev_line; /* needed for stepping */
-#endif
- duk_small_uint_t flags;
- /* idx_bottom and idx_retval are only used for book-keeping of
- * Ecmascript-initiated calls, to allow returning to an Ecmascript
- * function properly. They are duk_size_t to match the convention
- * that value stack sizes are duk_size_t and local frame indices
- * are duk_idx_t.
+ /* bottom_byteoff and retval_byteoff are only used for book-keeping
+ * of Ecmascript-initiated calls, to allow returning to an Ecmascript
+ * function properly.
*/
/* Bottom of valstack for this activation, used to reset
- * valstack_bottom on return; index is absolute. Note:
- * idx_top not needed because top is set to 'nregs' always
- * when returning to an Ecmascript activation.
+ * valstack_bottom on return; offset is absolute. There's
+ * no need to track 'top' because native call handling deals
+ * with that using locals, and for Ecmascript returns 'nregs'
+ * indicates the necessary top.
*/
- duk_size_t idx_bottom;
+ duk_size_t bottom_byteoff;
/* Return value when returning to this activation (points to caller
- * reg, not callee reg); index is absolute (only set if activation is
+ * reg, not callee reg); offset is absolute (only set if activation is
* not topmost).
*
- * Note: idx_bottom is always set, while idx_retval is only applicable
- * for activations below the topmost one. Currently idx_retval for
- * the topmost activation is considered garbage (and it not initialized
- * on entry or cleared on return; may contain previous or garbage
- * values).
+ * Note: bottom_byteoff is always set, while retval_byteoff is only
+ * applicable for activations below the topmost one. Currently
+ * retval_byteoff for the topmost activation is considered garbage
+ * (and it not initialized on entry or cleared on return; may contain
+ * previous or garbage values).
*/
- duk_size_t idx_retval;
+ duk_size_t retval_byteoff;
- /* Current 'this' binding is the value just below idx_bottom.
+ /* Current 'this' binding is the value just below bottom.
* Previously, 'this' binding was handled with an index to the
* (calling) valstack. This works for everything except tail
- * calls, which must not "cumulate" valstack temps.
+ * calls, which must not "accumulate" valstack temps.
*/
+
+ /* Value stack reserve (valstack_end) byte offset to be restored
+ * when returning to this activation. Only used by the bytecode
+ * executor.
+ */
+ duk_size_t reserve_byteoff;
+
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_uint32_t prev_line; /* needed for stepping */
+#endif
+
+ duk_small_uint_t flags;
};
-/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
struct duk_catcher {
+ duk_catcher *parent; /* previous (parent) catcher (or NULL if none) */
duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
/* (reference is valid as long activation exists) */
duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
- duk_size_t callstack_index; /* callstack index of related activation */
duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
duk_uint32_t flags; /* type and control flags, label number */
+ /* XXX: could pack 'flags' and 'idx_base' to same value in practice,
+ * on 32-bit targets this would make duk_catcher 16 bytes.
+ */
};
struct duk_hthread {
@@ -7406,40 +7591,49 @@ struct duk_hthread {
duk_uint8_t unused1;
duk_uint8_t unused2;
- /* Sanity limits for stack sizes. */
- duk_size_t valstack_max;
- duk_size_t callstack_max;
- duk_size_t catchstack_max;
-
- /* XXX: Valstack, callstack, and catchstack are currently assumed
- * to have non-NULL pointers. Relaxing this would not lead to big
- * benefits (except perhaps for terminated threads).
+ /* XXX: Valstack and callstack are currently assumed to have non-NULL
+ * pointers. Relaxing this would not lead to big benefits (except
+ * perhaps for terminated threads).
*/
- /* Value stack: these are expressed as pointers for faster stack manipulation.
- * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is
- * not GC-reachable but kept initialized as 'undefined'.
+ /* Value stack: these are expressed as pointers for faster stack
+ * manipulation. [valstack,valstack_top[ is GC-reachable,
+ * [valstack_top,valstack_alloc_end[ is not GC-reachable but kept
+ * initialized as 'undefined'. [valstack,valstack_end[ is the
+ * guaranteed/reserved space and the valstack cannot be resized to
+ * a smaller size. [valstack_end,valstack_alloc_end[ is currently
+ * allocated slack that can be used to grow the current guaranteed
+ * space but may be shrunk away without notice.
+ *
+ *
+ * <----------------------- guaranteed --->
+ * <---- slack --->
+ * <--- frame --->
+ * .-------------+=============+----------+--------------.
+ * |xxxxxxxxxxxxx|yyyyyyyyyyyyy|uuuuuuuuuu|uuuuuuuuuuuuuu|
+ * `-------------+=============+----------+--------------'
+ *
+ * ^ ^ ^ ^ ^
+ * | | | | |
+ * valstack bottom top end alloc_end
+ *
+ * xxx = arbitrary values, below current frame
+ * yyy = arbitrary values, inside current frame
+ * uuu = outside active value stack, initialized to 'undefined'
*/
duk_tval *valstack; /* start of valstack allocation */
- duk_tval *valstack_end; /* end of valstack allocation (exclusive) */
+ duk_tval *valstack_end; /* end of valstack reservation/guarantee (exclusive) */
+ duk_tval *valstack_alloc_end; /* end of valstack allocation */
duk_tval *valstack_bottom; /* bottom of current frame */
duk_tval *valstack_top; /* top of current frame (exclusive) */
-#if !defined(DUK_USE_PREFER_SIZE)
- duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */
-#endif
- /* Call stack. [0,callstack_top[ is GC reachable. */
- duk_activation *callstack;
+ /* Call stack, represented as a linked list starting from the current
+ * activation (or NULL if nothing is active).
+ */
duk_activation *callstack_curr; /* current activation (or NULL if none) */
- duk_size_t callstack_size; /* allocation size */
- duk_size_t callstack_top; /* next to use, highest used is top - 1 (or none if top == 0) */
+ duk_size_t callstack_top; /* number of activation records in callstack (0 if none) */
duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
- /* Catch stack. [0,catchstack_top[ is GC reachable. */
- duk_catcher *catchstack;
- duk_size_t catchstack_size; /* allocation size */
- duk_size_t catchstack_top; /* next to use, highest used is top - 1 */
-
/* Yield/resume book-keeping. */
duk_hthread *resumer; /* who resumed us (if any) */
@@ -7492,24 +7686,22 @@ DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top);
-DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top);
+DUK_INTERNAL_DECL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act);
+DUK_INTERNAL_DECL void duk_hthread_activation_unwind_norz(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level);
+
+DUK_INTERNAL_DECL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr);
+DUK_INTERNAL_DECL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat);
+DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act);
+DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act);
#if defined(DUK_USE_FINALIZER_TORTURE)
DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_torture_realloc(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr);
#endif
DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
@@ -7521,7 +7713,7 @@ DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
#endif /* DUK_HTHREAD_H_INCLUDED */
/* #include duk_harray.h */
/*
- * Heap Array object representation. Used for actual Array instances.
+ * Array object representation, used for actual Array instances.
*
* All objects with the exotic array behavior (which must coincide with having
* internal class array) MUST be duk_harrays. No other object can be a
@@ -7598,7 +7790,7 @@ struct duk_hdecenv {
*/
duk_hthread *thread;
duk_hobject *varmap;
- duk_size_t regbase;
+ duk_size_t regbase_byteoff;
};
struct duk_hobjenv {
@@ -7674,9 +7866,6 @@ struct duk_hobjenv {
* Field access
*/
-/* Get/set the current user visible size, without accounting for a dynamic
- * buffer's "spare" (= usable size).
- */
#if defined(DUK_USE_BUFLEN16)
/* size stored in duk_heaphdr unused flag bits */
#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
@@ -7796,7 +7985,7 @@ struct duk_hbuffer {
* it is useful for writing robust native code.
*/
- /* Current size (not counting a dynamic buffer's "spare"). */
+ /* Current size. */
#if defined(DUK_USE_BUFLEN16)
/* Stored in duk_heaphdr unused flags. */
#else
@@ -7945,6 +8134,33 @@ DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic
DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
#endif /* DUK_HBUFFER_H_INCLUDED */
+/* #include duk_hproxy.h */
+/*
+ * Proxy object representation.
+ */
+
+#if !defined(DUK_HPROXY_H_INCLUDED)
+#define DUK_HPROXY_H_INCLUDED
+
+#define DUK_ASSERT_HPROXY_VALID(h) do { \
+ DUK_ASSERT((h) != NULL); \
+ DUK_ASSERT((h)->target != NULL); \
+ DUK_ASSERT((h)->handler != NULL); \
+ DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) (h))); \
+ } while (0)
+
+struct duk_hproxy {
+ /* Shared object part. */
+ duk_hobject obj;
+
+ /* Proxy target object. */
+ duk_hobject *target;
+
+ /* Proxy handlers (traps). */
+ duk_hobject *handler;
+};
+
+#endif /* DUK_HPROXY_H_INCLUDED */
/* #include duk_heap.h */
/*
* Heap structure.
@@ -7962,11 +8178,10 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
* Heap flags
*/
-#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
-#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 1) /* an error handler (user callback to augment/replace error) is running */
-#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 2) /* executor interrupt running (used to avoid nested interrupts) */
-#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 3) /* heap destruction ongoing, finalizer rescue no longer possible */
-#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 4) /* debugger is paused: talk with debug client until step/resume */
+#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1U << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
+#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1U << 1) /* executor interrupt running (used to avoid nested interrupts) */
+#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1U << 2) /* heap destruction ongoing, finalizer rescue no longer possible */
+#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1U << 3) /* debugger is paused: talk with debug client until step/resume */
#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
@@ -7977,19 +8192,16 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
} while (0)
#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
@@ -8018,22 +8230,22 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
/* Emergency mark-and-sweep: try extra hard, even at the cost of
* performance.
*/
-#define DUK_MS_FLAG_EMERGENCY (1 << 0)
+#define DUK_MS_FLAG_EMERGENCY (1U << 0)
/* Voluntary mark-and-sweep: triggered periodically. */
-#define DUK_MS_FLAG_VOLUNTARY (1 << 1)
+#define DUK_MS_FLAG_VOLUNTARY (1U << 1)
/* Postpone rescue decisions for reachable objects with FINALIZED set.
* Used during finalize_list processing to avoid incorrect rescue
* decisions due to finalize_list being a reachability root.
*/
-#define DUK_MS_FLAG_POSTPONE_RESCUE (1 << 2)
+#define DUK_MS_FLAG_POSTPONE_RESCUE (1U << 2)
/* Don't compact objects; needed during object property table resize
* to prevent a recursive resize. It would suffice to protect only the
* current object being resized, but this is not yet implemented.
*/
-#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2)
+#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1U << 3)
/*
* Thread switching
@@ -8052,6 +8264,18 @@ DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *
#endif
/*
+ * Stats
+ */
+
+#if defined(DUK_USE_DEBUG)
+#define DUK_STATS_INC(heap,fieldname) do { \
+ (heap)->fieldname += 1; \
+ } while (0)
+#else
+#define DUK_STATS_INC(heap,fieldname) do {} while (0)
+#endif
+
+/*
* Other heap related defines
*/
@@ -8168,10 +8392,14 @@ typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
/*
* Checked allocation, relative to a thread
+ *
+ * DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument
+ * for convenience.
*/
#define DUK_ALLOC_CHECKED(thr,size) duk_heap_mem_alloc_checked((thr), (size))
#define DUK_ALLOC_CHECKED_ZEROED(thr,size) duk_heap_mem_alloc_checked_zeroed((thr), (size))
+#define DUK_FREE_CHECKED(thr,ptr) duk_heap_mem_free((thr)->heap, (ptr))
/*
* Memory constants
@@ -8207,11 +8435,14 @@ typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
/* Milliseconds between status notify and transport peeks. */
#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
-/* Step types */
-#define DUK_STEP_TYPE_NONE 0
-#define DUK_STEP_TYPE_INTO 1
-#define DUK_STEP_TYPE_OVER 2
-#define DUK_STEP_TYPE_OUT 3
+/* Debugger pause flags. */
+#define DUK_PAUSE_FLAG_ONE_OPCODE (1U << 0) /* pause when a single opcode has been executed */
+#define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1) /* one opcode pause actually active; artifact of current implementation */
+#define DUK_PAUSE_FLAG_LINE_CHANGE (1U << 2) /* pause when current line number changes */
+#define DUK_PAUSE_FLAG_FUNC_ENTRY (1U << 3) /* pause when entering a function */
+#define DUK_PAUSE_FLAG_FUNC_EXIT (1U << 4) /* pause when exiting current function */
+#define DUK_PAUSE_FLAG_CAUGHT_ERROR (1U << 5) /* pause when about to throw an error that is caught */
+#define DUK_PAUSE_FLAG_UNCAUGHT_ERROR (1U << 6) /* pause when about to throw an error that won't be caught */
struct duk_breakpoint {
duk_hstring *filename;
@@ -8307,6 +8538,14 @@ struct duk_heap {
#endif
#endif
+ /* Freelist for duk_activations and duk_catchers. */
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ duk_activation *activation_free;
+#endif
+#if defined(DUK_USE_CACHE_CATCHER)
+ duk_catcher *catcher_free;
+#endif
+
/* Voluntary mark-and-sweep trigger counter. Intentionally signed
* because we continue decreasing the value when voluntary GC cannot
* run.
@@ -8370,6 +8609,14 @@ struct duk_heap {
*/
duk_bool_t creating_error;
+ /* Marker for indicating we're calling a user error augmentation
+ * (errCreate/errThrow) function. Errors created/thrown during
+ * such a call are not augmented.
+ */
+#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ duk_bool_t augmenting_error;
+#endif
+
/* Longjmp state. */
duk_ljstate lj;
@@ -8431,23 +8678,25 @@ struct duk_heap {
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 */
- duk_uint32_t dbg_step_startline; /* starting line number */
+ duk_small_uint_t dbg_pause_flags; /* flags for automatic pause behavior */
+ duk_activation *dbg_pause_act; /* activation related to pause behavior (pause on line change, function entry/exit) */
+ duk_uint32_t dbg_pause_startline; /* starting line number for line change related pause behavior */
duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
duk_small_uint_t dbg_breakpoint_count;
duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
/* XXX: make active breakpoints actual copies instead of pointers? */
/* These are for rate limiting Status notifications and transport peeking. */
- 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_uint_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
+ duk_uint_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 /* DUK_USE_DEBUGGER_SUPPORT */
+#if defined(DUK_USE_ASSERTIONS)
+ duk_bool_t dbg_calling_transport; /* transport call in progress, calling into Duktape forbidden */
#endif
/* String intern table (weak refs). */
@@ -8478,6 +8727,51 @@ struct duk_heap {
duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
#endif
#endif
+
+ /* Stats. */
+#if defined(DUK_USE_DEBUG)
+ duk_int_t stats_exec_opcodes;
+ duk_int_t stats_exec_interrupt;
+ duk_int_t stats_exec_throw;
+ duk_int_t stats_call_all;
+ duk_int_t stats_call_tailcall;
+ duk_int_t stats_call_ecmatoecma;
+ duk_int_t stats_safecall_all;
+ duk_int_t stats_safecall_nothrow;
+ duk_int_t stats_safecall_throw;
+ duk_int_t stats_ms_try_count;
+ duk_int_t stats_ms_skip_count;
+ duk_int_t stats_ms_emergency_count;
+ duk_int_t stats_strtab_intern_hit;
+ duk_int_t stats_strtab_intern_miss;
+ duk_int_t stats_strtab_resize_check;
+ duk_int_t stats_strtab_resize_grow;
+ duk_int_t stats_strtab_resize_shrink;
+ duk_int_t stats_object_realloc_props;
+ duk_int_t stats_object_abandon_array;
+ duk_int_t stats_getownpropdesc_count;
+ duk_int_t stats_getownpropdesc_hit;
+ duk_int_t stats_getownpropdesc_miss;
+ duk_int_t stats_getpropdesc_count;
+ duk_int_t stats_getpropdesc_hit;
+ duk_int_t stats_getpropdesc_miss;
+ duk_int_t stats_getprop_all;
+ duk_int_t stats_getprop_arrayidx;
+ duk_int_t stats_getprop_bufobjidx;
+ duk_int_t stats_getprop_bufferidx;
+ duk_int_t stats_getprop_bufferlen;
+ duk_int_t stats_getprop_stringidx;
+ duk_int_t stats_getprop_stringlen;
+ duk_int_t stats_getprop_proxy;
+ duk_int_t stats_getprop_arguments;
+ duk_int_t stats_putprop_all;
+ duk_int_t stats_putprop_arrayidx;
+ duk_int_t stats_putprop_bufobjidx;
+ duk_int_t stats_putprop_bufferidx;
+ duk_int_t stats_putprop_proxy;
+ duk_int_t stats_getvar_all;
+ duk_int_t stats_putvar_all;
+#endif
};
/*
@@ -8542,6 +8836,8 @@ DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size
DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
+DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap);
+
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj);
DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap);
@@ -8628,8 +8924,8 @@ DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uin
/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
* The remaining flags are specific to the debugger.
*/
-#define DUK_DBG_PROPFLAG_SYMBOL (1 << 8)
-#define DUK_DBG_PROPFLAG_HIDDEN (1 << 9)
+#define DUK_DBG_PROPFLAG_SYMBOL (1U << 8)
+#define DUK_DBG_PROPFLAG_HIDDEN (1U << 9)
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
@@ -8700,7 +8996,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap);
DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap);
DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap);
DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap);
-DUK_INTERNAL_DECL void duk_debug_clear_step_state(duk_heap *heap);
+DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap);
#endif /* DUK_USE_DEBUGGER_SUPPORT */
#endif /* DUK_DEBUGGER_H_INCLUDED */
@@ -9063,6 +9359,10 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#define DUK_ERROR_INTERNAL(thr) do { \
duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
+#define DUK_DCERROR_INTERNAL(thr) do { \
+ DUK_ERROR_INTERNAL((thr)); \
+ return 0; \
+ } while (0)
#define DUK_ERROR_ALLOC_FAILED(thr) do { \
duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
@@ -9088,6 +9388,10 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \
} while (0)
+#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_ERROR_RANGE_INVALID_COUNT((thr)); \
+ return 0; \
+ } while (0)
#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \
} while (0)
@@ -9143,6 +9447,10 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#define DUK_ERROR_INTERNAL(thr) do { \
duk_err_error((thr)); \
} while (0)
+#define DUK_DCERROR_INTERNAL(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_ERROR; \
+ } while (0)
#define DUK_ERROR_ALLOC_FAILED(thr) do { \
duk_err_error((thr)); \
} while (0)
@@ -9168,6 +9476,10 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
duk_err_range((thr)); \
} while (0)
+#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
+ DUK_UNREF((thr)); \
+ return DUK_RET_RANGE_ERROR; \
+ } while (0)
#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
duk_err_range((thr)); \
} while (0)
@@ -9293,6 +9605,19 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
DUK_ASSERT(thr->valstack_top < thr->valstack_end)
/*
+ * Helper to initialize a memory area (e.g. struct) with garbage when
+ * assertions enabled.
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
+ DUK_MEMSET((void *) (ptr), 0x5a, size); \
+ } while (0)
+#else
+#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)
+#endif
+
+/*
* Helper for valstack space
*
* Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
@@ -9331,8 +9656,11 @@ DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, d
DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
+#define DUK_AUGMENT_FLAG_NOBLAME_FILELINE (1U << 0) /* if set, don't blame C file/line for .fileName and .lineNumber */
+#define DUK_AUGMENT_FLAG_SKIP_ONE (1U << 1) /* if set, skip topmost activation in traceback construction */
+
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline);
+DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_small_uint_t flags);
#endif
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
@@ -9613,6 +9941,17 @@ extern const duk_uint8_t duk_unicode_caseconv_lc[680];
extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
#endif
+#if defined(DUK_USE_REGEXP_CANON_BITMAP)
+/*
+ * Automatically generated by extract_caseconv.py, do not edit!
+ */
+
+#define DUK_CANON_BITMAP_BLKSIZE 32
+#define DUK_CANON_BITMAP_BLKSHIFT 5
+#define DUK_CANON_BITMAP_BLKMASK 31
+extern const duk_uint8_t duk_unicode_re_canon_bitmap[256];
+#endif
+
/*
* Extern
*/
@@ -9663,10 +10002,10 @@ DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp)
#define DUK_JSON_H_INCLUDED
/* Encoding/decoding flags */
-#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */
-#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */
-#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */
-#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */
+#define DUK_JSON_FLAG_ASCII_ONLY (1U << 0) /* escape any non-ASCII characters */
+#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1U << 1) /* avoid key quotes when key is an ASCII Identifier */
+#define DUK_JSON_FLAG_EXT_CUSTOM (1U << 2) /* extended types: custom encoding */
+#define DUK_JSON_FLAG_EXT_COMPATIBLE (1U << 3) /* extended types: compatible encoding */
/* How much stack to require on entry to object/array encode */
#define DUK_JSON_ENC_REQSTACK 32
@@ -9693,8 +10032,8 @@ typedef struct {
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;
+ duk_uint_t recursion_depth;
+ duk_uint_t recursion_limit;
duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
duk_small_uint_t stridx_custom_undefined;
@@ -9731,20 +10070,22 @@ typedef struct {
#if !defined(DUK_JS_H_INCLUDED)
#define DUK_JS_H_INCLUDED
-/* Flags for call handling. */
-#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
-#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
-#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
-#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
-#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
+/* Flags for call handling. Lowest flags must match bytecode DUK_BC_CALL_FLAG_xxx 1:1. */
+#define DUK_CALL_FLAG_TAILCALL (1U << 0) /* setup for a tail call */
+#define DUK_CALL_FLAG_CONSTRUCT (1U << 1) /* constructor call (i.e. called as 'new Foo()') */
+#define DUK_CALL_FLAG_CALLED_AS_EVAL (1U << 2) /* call was made using the identifier 'eval' */
+#define DUK_CALL_FLAG_ALLOW_ECMATOECMA (1U << 3) /* ecma-to-ecma call with executor reuse is possible */
+#define DUK_CALL_FLAG_DIRECT_EVAL (1U << 4) /* call is a direct eval call */
+#define DUK_CALL_FLAG_CONSTRUCT_PROXY (1U << 5) /* handled via 'construct' proxy trap, check return value invariant(s) */
+#define DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED (1U << 6) /* prototype of 'default instance' updated, temporary flag in call handling */
/* Flags for duk_js_equals_helper(). */
-#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
-#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */
+#define DUK_EQUALS_FLAG_SAMEVALUE (1U << 0) /* use SameValue instead of non-strict equality */
+#define DUK_EQUALS_FLAG_STRICT (1U << 1) /* use strict equality instead of non-strict equality */
/* Flags for duk_js_compare_helper(). */
-#define DUK_COMPARE_FLAG_NEGATE (1 << 0) /* negate result */
-#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 1) /* eval left argument first */
+#define DUK_COMPARE_FLAG_NEGATE (1U << 0) /* negate result */
+#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1U << 1) /* eval left argument first */
/* conversions, coercions, comparison, etc */
DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
@@ -9759,13 +10100,13 @@ DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *s
DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h);
DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h);
#endif
-DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
+DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2);
DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
#if 0 /* unused */
DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
#endif
-DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
+DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x);
@@ -9809,22 +10150,24 @@ DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation
DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
#endif
DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
-DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl);
+DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_uint_t prop_flags, duk_bool_t is_func_decl);
DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env);
-DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom);
-DUK_INTERNAL_DECL
-void duk_js_push_closure(duk_hthread *thr,
- duk_hcompfunc *fun_temp,
- duk_hobject *outer_var_env,
- duk_hobject *outer_lex_env,
- duk_bool_t add_auto_proto);
+DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t bottom_byteoff);
+DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr,
+ duk_hcompfunc *fun_temp,
+ duk_hobject *outer_var_env,
+ duk_hobject *outer_lex_env,
+ duk_bool_t add_auto_proto);
/* call handling */
-DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
-DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t idx_func, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
-DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant);
+#if defined(DUK_USE_VERBOSE_ERRORS)
+DUK_INTERNAL_DECL void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key);
+#endif
/* bytecode execution */
DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
@@ -9842,23 +10185,23 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
/* Output a specified number of digits instead of using the shortest
* form. Used for toPrecision() and toFixed().
*/
-#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0)
+#define DUK_N2S_FLAG_FIXED_FORMAT (1U << 0)
/* Force exponential format. Used for toExponential(). */
-#define DUK_N2S_FLAG_FORCE_EXP (1 << 1)
+#define DUK_N2S_FLAG_FORCE_EXP (1U << 1)
/* If number would need zero padding (for whole number part), use
* exponential format instead. E.g. if input number is 12300, 3
* digits are generated ("123"), output "1.23e+4" instead of "12300".
* Used for toPrecision().
*/
-#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2)
+#define DUK_N2S_FLAG_NO_ZERO_PAD (1U << 2)
/* Digit count indicates number of fractions (i.e. an absolute
* digit index instead of a relative one). Used together with
* DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
*/
-#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3)
+#define DUK_N2S_FLAG_FRACTION_DIGITS (1U << 3)
/*
* String-to-number conversion
@@ -9871,64 +10214,64 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
#define DUK_S2N_MAX_EXPONENT 1000000000
/* Trim white space (= allow leading and trailing whitespace) */
-#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0)
+#define DUK_S2N_FLAG_TRIM_WHITE (1U << 0)
/* Allow exponent */
-#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1)
+#define DUK_S2N_FLAG_ALLOW_EXP (1U << 1)
/* Allow trailing garbage (e.g. treat "123foo" as "123) */
-#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2)
+#define DUK_S2N_FLAG_ALLOW_GARBAGE (1U << 2)
/* Allow leading plus sign */
-#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3)
+#define DUK_S2N_FLAG_ALLOW_PLUS (1U << 3)
/* Allow leading minus sign */
-#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4)
+#define DUK_S2N_FLAG_ALLOW_MINUS (1U << 4)
/* Allow 'Infinity' */
-#define DUK_S2N_FLAG_ALLOW_INF (1 << 5)
+#define DUK_S2N_FLAG_ALLOW_INF (1U << 5)
/* Allow fraction part */
-#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6)
+#define DUK_S2N_FLAG_ALLOW_FRAC (1U << 6)
/* Allow naked fraction (e.g. ".123") */
-#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7)
+#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1U << 7)
/* Allow empty fraction (e.g. "123.") */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8)
+#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1U << 8)
/* Allow empty string to be interpreted as 0 */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9)
+#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1U << 9)
/* Allow leading zeroes (e.g. "0123" -> "123") */
-#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10)
+#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1U << 10)
/* Allow automatic detection of hex base ("0x" or "0X" prefix),
* overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11)
+#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1U << 11)
/* Allow automatic detection of legacy octal base ("0n"),
* overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1 << 12)
+#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1U << 12)
/* Allow automatic detection of ES2015 octal base ("0o123"),
* overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 13)
+#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1U << 13)
/* Allow automatic detection of ES2015 binary base ("0b10001"),
* overrides radix argument and forces integer mode.
*/
-#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1 << 14)
+#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1U << 14)
/*
* Prototypes
*/
-DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
+DUK_INTERNAL_DECL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags);
#endif /* DUK_NUMCONV_H_INCLUDED */
/* #include duk_bi_protos.h */
@@ -9957,13 +10300,16 @@ 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);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void);
#endif
#if defined(DUK_USE_DATE_NOW_TIME)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void);
#endif
#if defined(DUK_USE_DATE_NOW_WINDOWS)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void);
+#endif
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void);
#endif
#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
@@ -9975,31 +10321,38 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(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);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, 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);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, 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);
+DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
+#endif
+
+#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void);
+#endif
+#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void);
#endif
DUK_INTERNAL_DECL
-void duk_bi_json_parse_helper(duk_context *ctx,
+void duk_bi_json_parse_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags);
DUK_INTERNAL_DECL
-void duk_bi_json_stringify_helper(duk_context *ctx,
+void duk_bi_json_stringify_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags);
-DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr);
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h_proxy_target, duk_uint_t flags);
+DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags);
#endif
#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
@@ -10200,7 +10553,7 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
#if defined(DUK_USE_ROM_STRINGS)
#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
-DUK_INTERNAL const duk_uint8_t duk_strings_data[903] = {
+DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = {
79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
@@ -10221,38 +10574,37 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[903] = {
67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2,
249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
-32,45,100,139,134,69,146,100,227,226,231,146,51,192,204,73,140,224,145,221,
-102,241,68,196,157,34,79,143,139,166,233,225,228,227,138,157,173,167,197,
-211,118,214,210,38,238,74,113,67,76,105,187,169,147,154,73,225,228,32,193,
-48,25,100,105,166,113,200,147,44,166,1,40,79,18,150,134,147,141,163,2,72,
-171,115,147,136,4,65,130,96,35,64,194,32,168,89,56,208,48,135,123,144,217,
-146,38,220,229,64,186,16,187,156,105,47,52,238,112,56,153,4,225,145,27,156,
-43,162,192,46,71,220,229,65,22,1,231,220,228,157,72,136,136,220,227,197,
-164,180,52,133,220,228,206,137,23,115,128,137,164,77,206,48,15,62,231,42,8,
-145,181,86,231,10,134,129,104,201,34,125,206,76,17,49,38,141,206,28,13,26,
-201,19,137,204,122,22,66,161,175,164,210,72,199,130,137,1,50,32,145,143,38,
-120,186,195,35,106,51,146,230,8,36,77,109,65,38,226,72,141,18,74,140,35,
-247,247,182,168,209,144,187,223,58,156,104,79,190,183,127,123,105,160,110,
-247,206,167,26,19,239,173,223,222,218,67,75,189,243,169,198,132,251,235,
-183,247,182,154,134,151,123,231,83,141,9,247,215,111,239,109,22,141,22,247,
-206,167,26,19,239,172,223,218,45,26,47,157,78,52,39,223,74,24,144,10,32,
-129,34,20,64,152,142,129,57,179,67,104,68,12,129,161,140,72,156,100,40,40,
-185,152,100,89,38,65,13,196,34,228,67,149,13,2,215,129,149,209,65,104,209,
-77,14,104,144,81,33,170,67,101,48,52,68,113,70,210,88,209,36,233,22,154,86,
-68,196,114,76,232,145,102,120,186,195,156,112,105,225,228,113,71,80,68,162,
-115,101,50,85,200,25,108,116,44,132,178,38,114,137,96,148,136,70,209,134,
-37,222,232,204,228,188,200,209,200,200,99,221,25,150,84,121,34,70,209,107,
-36,227,66,20,160,92,136,164,49,235,35,8,217,201,40,108,201,18,128,68,26,
-201,51,188,2,80,12,67,190,40,168,38,68,190,46,153,5,50,12,207,160,86,129,
-26,83,4,208,34,225,4,88,192,
+32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226,
+231,146,51,192,204,73,140,224,145,221,102,241,68,196,157,34,79,143,139,166,
+233,225,228,227,138,157,173,167,197,211,118,214,210,38,238,74,113,67,76,
+105,187,169,147,154,73,225,228,32,193,48,25,100,105,166,113,200,147,44,166,
+1,40,79,18,150,134,147,141,163,2,72,171,115,147,136,4,65,130,96,35,64,194,
+32,168,89,56,208,48,135,123,144,217,146,39,220,228,193,19,18,101,220,227,
+73,121,167,115,129,196,200,39,12,136,220,225,93,22,1,114,62,231,42,8,176,
+15,62,231,36,234,68,68,70,231,30,45,37,161,164,38,231,24,7,159,115,149,4,
+72,218,171,115,133,67,64,180,100,145,54,231,42,5,208,135,19,152,244,44,133,
+67,95,73,164,145,143,5,18,2,100,65,35,30,76,241,117,134,70,212,103,37,204,
+16,72,154,218,130,77,196,145,63,127,123,106,141,25,11,189,243,169,198,132,
+251,235,119,247,182,154,6,239,124,234,113,161,62,250,221,253,237,164,52,
+187,223,58,156,104,79,190,187,127,123,105,168,105,119,190,117,56,208,159,
+125,118,254,246,209,104,209,111,124,234,113,161,62,250,205,253,162,209,162,
+249,212,227,66,125,244,161,137,0,162,8,18,33,68,9,136,232,19,155,52,54,132,
+64,200,26,24,196,137,198,66,130,139,153,134,69,146,100,16,220,66,46,68,57,
+80,208,45,120,25,93,20,22,141,20,208,230,137,5,18,26,164,54,83,3,68,71,20,
+109,37,141,18,78,145,105,165,100,76,71,36,206,137,22,103,139,172,57,199,6,
+158,30,71,20,117,4,74,39,54,83,37,92,129,150,199,66,200,75,34,103,40,150,9,
+72,132,109,24,98,93,238,140,206,75,204,141,28,140,134,61,209,153,101,71,
+146,36,109,22,178,78,52,33,74,5,200,138,67,30,178,48,141,156,146,134,204,
+145,40,4,65,172,147,59,192,37,0,196,59,226,138,130,100,75,226,233,144,83,
+32,204,250,5,104,17,165,48,77,2,46,16,69,140,
};
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_OBJECTS */
-/* native functions: 166 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[166] = {
+/* native functions: 176 */
+DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = {
NULL,
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
@@ -10324,12 +10676,17 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[166] = {
duk_bi_global_object_unescape,
duk_bi_json_object_parse,
duk_bi_json_object_stringify,
+ duk_bi_math_object_clz32,
duk_bi_math_object_hypot,
+ duk_bi_math_object_imul,
duk_bi_math_object_max,
duk_bi_math_object_min,
duk_bi_math_object_onearg_shared,
duk_bi_math_object_random,
+ duk_bi_math_object_sign,
duk_bi_math_object_twoarg_shared,
+ duk_bi_native_function_length,
+ duk_bi_native_function_name,
duk_bi_nodejs_buffer_byte_length,
duk_bi_nodejs_buffer_concat,
duk_bi_nodejs_buffer_constructor,
@@ -10360,16 +10717,21 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[166] = {
duk_bi_object_constructor_prevent_extensions,
duk_bi_object_constructor_seal_freeze_shared,
duk_bi_object_getprototype_shared,
+ duk_bi_object_prototype_defineaccessor,
duk_bi_object_prototype_has_own_property,
duk_bi_object_prototype_is_prototype_of,
+ duk_bi_object_prototype_lookupaccessor,
duk_bi_object_prototype_property_is_enumerable,
duk_bi_object_prototype_to_locale_string,
duk_bi_object_prototype_to_string,
duk_bi_object_prototype_value_of,
duk_bi_object_setprototype_shared,
+ duk_bi_performance_now,
duk_bi_pointer_constructor,
duk_bi_pointer_prototype_tostring_shared,
duk_bi_proxy_constructor,
+ duk_bi_reflect_apply,
+ duk_bi_reflect_construct,
duk_bi_reflect_object_delete_property,
duk_bi_reflect_object_get,
duk_bi_reflect_object_has,
@@ -10421,541 +10783,556 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[166] = {
duk_bi_uint8array_plainof,
};
#if defined(DUK_USE_DOUBLE_LE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = {
-144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191,
-135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196,
-52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26,
-98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212,
-132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78,
-18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59,
-147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17,
-171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120,
-121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215,
-254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85,
-217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50,
-70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,0,0,0,0,15,
-135,252,204,0,0,0,0,0,0,15,7,252,188,72,6,176,77,225,28,24,103,14,33,197,
-138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64,
-211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228,
-176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40,
-39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175,
-131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243,
-200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76,
-151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238,
-108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128,
-168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101,
-136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201,
-218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196,
-144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62,
-46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185,
-228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207,
-36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64,
-112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52,
-18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18,
-243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70,
-240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111,
-31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230,
-144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60,
-113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120,
-226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215,
-140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135,
-33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73,
-30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78,
-140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142,
-43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136,
-6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21,
-11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15,
-224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23,
-51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238,
-0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61,
-200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172,
-18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158,
-66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44,
-150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46,
-110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224,
-129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39,
-40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48,
-70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131,
-36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97,
-103,129,6,73,0,79,88,11,237,84,11,161,32,127,255,255,255,255,255,247,191,
-137,235,16,221,170,129,116,36,0,16,0,0,0,0,0,0,12,196,0,0,0,0,0,0,15,135,
-242,61,123,164,137,162,164,218,67,74,134,162,120,128,0,0,0,0,0,1,224,254,
-71,173,33,129,52,84,155,72,105,80,212,79,16,0,0,0,0,0,0,60,63,199,36,38,
-218,0,0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,
-123,82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,
-230,237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,
-57,41,54,210,0,0,0,0,0,0,62,31,241,58,155,192,12,155,184,48,76,156,148,226,
-134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184,
-183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37,
-56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52,
-48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246,
-139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103,
-92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75,
-33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147,
-225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227,
-16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137,
-62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152,
-147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18,
-32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228,
-73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79,
-180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142,
-86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134,
-210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145,
-39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30,
-68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124,
-99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73,
-240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27,
-111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3,
-147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24,
-172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64,
-65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108,
-115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49,
-116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137,
-213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192,
-158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46,
-204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180,
-138,9,216,197,209,200,148,161,194,32,30,18,3,74,184,164,88,85,248,42,0,78,
-173,186,58,16,5,149,109,110,236,90,192,144,1,245,109,210,129,222,115,245,
-252,132,93,204,126,23,171,113,180,137,3,250,8,173,149,28,87,220,252,55,86,
-227,104,232,18,0,119,41,48,171,222,94,217,248,46,189,16,6,11,81,21,62,200,
-66,80,3,246,80,140,244,118,180,160,102,157,191,179,79,80,115,31,133,236,
-161,25,233,64,205,59,127,102,158,160,246,63,41,248,30,75,12,11,151,242,233,
-187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196,
-129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20,
-128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66,
-10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220,
-109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104,
-220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7,
-48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161,
-166,65,113,162,98,8,3,131,7,169,35,36,57,176,0,0,0,0,0,40,116,208,45,158,
-10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40,
-240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0,
-10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60,
-240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145,
-139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160,
-123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56,
-248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111,
-31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186,
-120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110,
-25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52,
-252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70,
-154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26,
-105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132,
-176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73,
-241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147,
-226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173,
-192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124,
-67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207,
-71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158,
-149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79,
-74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89,
-26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,
-130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,142,49,232,71,161,196,201,45,
-167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,141,201,8,71,161,196,201,
-45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,250,138,2,214,225,113,235,
-2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38,
-73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,80,66,61,14,
-38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,113,147,66,61,
-14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,60,15,204,110,88,66,
-61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113,149,
-66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,110,96,
-66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,113,
-151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,0,16,12,
-110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4,16,
-12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,4,
-16,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,0,
-4,16,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,0,
-0,4,16,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,0,
-0,0,4,16,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,
-0,0,0,4,16,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,
-0,0,0,0,8,16,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,
-0,0,0,0,0,8,16,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211,
-107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39,
-49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1,
-241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72,
-1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213,
-146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58,
-217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34,
-139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232,
-73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36,
-162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78,
-132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117,
-179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232,
-73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216,
-166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137,
-147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100,
-166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35,
-173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166,
-209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122,
-122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100,
-225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27,
-104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250,
-178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207,
-171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0,
-133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100,
-1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26,
-110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52,
-221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12,
-50,9,195,39,196,80,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,0,0,
+0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,172,19,120,71,10,25,196,136,
+113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,2,
+185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,130,
+249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,138,
+9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,190,15,
+38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,53,64,
+243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,124,
+35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,116,
+88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,240,70,
+68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,51,132,
+9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,105,27,
+60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,117,204,
+123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,65,112,
+152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,39,199,
+89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,58,205,
+227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,133,18,
+2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,39,31,23,
+60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,18,84,141,
+159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,194,197,
+217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,32,130,
+166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,151,21,0,
+100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,214,111,
+31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,10,62,
+46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,52,
+156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,255,255,255,255,
+239,127,19,214,33,187,85,2,232,72,0,32,0,0,0,0,0,0,25,136,0,0,0,0,0,0,31,
+15,228,122,247,73,19,69,73,180,134,149,13,68,241,0,0,0,0,0,0,3,193,252,143,
+90,67,2,104,169,54,144,210,161,168,158,32,0,0,0,0,0,0,120,127,142,73,78,20,
+0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,
+13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
+222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
+112,164,0,0,0,0,0,0,124,63,226,117,119,128,25,55,112,96,153,57,41,197,13,
+53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
+22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
+113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
+97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
+190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
+206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
+76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
+39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
+39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
+163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
+100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
+11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
+157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
+178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
+9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
+49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
+34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
+137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
+199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
+147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
+54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
+7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
+89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
+131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
+231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
+228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
+235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
+64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
+168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
+19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,0,0,0,0,93,105,160,91,
+60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,
+110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,
+36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,
+139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,
+28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,
+92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,
+100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,
+69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,
+68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,
+49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
+98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
+249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
+136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
+16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
+194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
+89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,104,71,161,196,201,45,167,146,59,
+68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,136,71,161,196,201,45,167,146,
+59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,168,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,200,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,232,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,8,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,40,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,72,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,52,102,32,76,72,1,246,136,235,
+103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
+171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
+158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
+246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
+37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
+75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
+39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
+129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
+17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
+207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
+207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
+78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
+146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
+104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
+146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
+217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
+162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
+77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
+117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
+162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
+102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
+72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,
+52,171,138,69,133,95,130,160,4,234,219,163,161,0,89,86,214,238,197,172,9,0,
+31,86,221,40,29,231,63,95,200,69,220,199,225,122,183,27,72,144,63,160,138,
+217,81,197,125,207,195,117,110,54,142,129,32,7,114,147,10,189,229,237,159,
+130,235,209,0,96,181,17,83,236,132,37,0,63,101,8,207,71,107,74,6,105,219,
+251,52,245,7,49,248,94,202,17,158,148,12,211,183,246,105,234,15,99,242,159,
+129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
+192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
+27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
+32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
+188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
+13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
+72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
+81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
+153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
+128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
+164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
+120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
+16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
+100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
+108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
+10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
+138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
+80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
+48,141,156,0,0,0,0,0,0,15,3,243,49,135,16,143,67,137,146,91,79,36,118,136,
+178,48,141,156,0,0,0,0,0,0,15,3,245,20,5,173,194,227,214,4,55,0,0,21,196,7,
+122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,0,0,0,0,120,31,153,140,72,132,122,28,76,146,218,121,
+35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,80,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,88,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,96,132,122,28,76,
+146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,104,132,122,
+28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,112,
+132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,16,32,16,
+113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,
+104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,
+165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,
+154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,
+147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#elif defined(DUK_USE_DOUBLE_BE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = {
-144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191,
-135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196,
-52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26,
-98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212,
-132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78,
-18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59,
-147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17,
-171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120,
-121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215,
-254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85,
-217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50,
-70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,7,255,128,0,0,
-0,0,0,12,204,7,255,0,0,0,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197,
-138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64,
-211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228,
-176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40,
-39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175,
-131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243,
-200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76,
-151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238,
-108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128,
-168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101,
-136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201,
-218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196,
-144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62,
-46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185,
-228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207,
-36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64,
-112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52,
-18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18,
-243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70,
-240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111,
-31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230,
-144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60,
-113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120,
-226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215,
-140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135,
-33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73,
-30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78,
-140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142,
-43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136,
-6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21,
-11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15,
-224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23,
-51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238,
-0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61,
-200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172,
-18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158,
-66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44,
-150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46,
-110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224,
-129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39,
-40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48,
-70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131,
-36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97,
-103,129,6,73,0,79,88,11,237,84,11,161,32,63,247,255,255,255,255,255,255,
-137,235,16,221,170,129,116,36,0,0,0,0,0,0,0,0,28,196,7,255,128,0,0,0,0,0,2,
-61,123,164,137,162,164,218,67,74,134,162,120,128,255,224,0,0,0,0,0,0,71,
-173,33,129,52,84,155,72,105,80,212,79,16,63,252,0,0,0,0,0,0,7,36,38,218,0,
-0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123,
-82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230,
-237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57,
-41,54,210,31,254,0,0,0,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226,
-134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184,
-183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37,
-56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52,
-48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246,
-139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103,
-92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75,
-33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147,
-225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227,
-16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137,
-62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152,
-147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18,
-32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228,
-73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79,
-180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142,
-86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134,
-210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145,
-39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30,
-68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124,
-99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73,
-240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27,
-111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3,
-147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24,
-172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64,
-65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108,
-115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49,
-116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137,
-213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192,
-158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46,
-204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180,
-138,9,216,197,209,200,148,161,194,32,30,18,2,0,45,248,84,88,162,187,72,78,
-173,186,58,16,16,0,154,236,110,237,85,69,129,245,109,210,128,127,204,92,
-133,253,244,115,222,23,171,113,180,137,0,255,220,85,29,148,174,11,248,55,
-86,227,104,232,18,1,254,222,91,216,169,55,40,112,46,189,16,16,2,72,126,213,
-17,11,70,3,246,80,140,244,118,180,160,31,243,80,79,51,63,157,230,133,236,
-161,25,233,64,63,246,160,158,102,127,59,205,41,248,30,75,12,11,151,242,233,
-187,146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196,
-129,1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20,
-128,130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66,
-10,124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220,
-109,29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104,
-220,205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7,
-48,55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161,
-166,65,113,162,98,8,3,131,7,169,35,36,57,176,16,52,232,64,0,0,0,0,45,158,
-10,225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40,
-240,25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0,
-10,79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60,
-240,76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145,
-139,163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160,
-123,215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56,
-248,185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111,
-31,23,60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186,
-120,121,56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110,
-25,49,23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52,
-252,212,87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70,
-154,103,143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26,
-105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132,
-176,230,36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73,
-241,13,158,142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147,
-226,27,61,61,42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173,
-192,158,158,149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124,
-67,103,177,77,177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207,
-71,90,155,99,68,200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158,
-149,54,199,9,145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79,
-74,155,94,21,34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89,
-26,105,158,63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,
-130,235,191,232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167,
-146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,142,49,232,71,161,196,201,45,
-167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,141,201,8,71,161,196,201,
-45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,2,138,2,214,225,113,235,
-2,27,128,0,10,66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38,
-73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,80,66,61,14,
-38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,113,147,66,61,
-14,38,73,109,60,145,218,34,200,194,54,112,15,252,0,0,0,0,0,0,12,110,88,66,
-61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113,149,
-66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,110,96,
-66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,113,
-151,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,0,0,0,0,0,0,0,12,
-110,104,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0,0,
-12,113,153,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,0,
-0,12,110,112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,0,
-0,0,12,113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,0,
-0,0,0,12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,0,
-0,0,0,0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,4,0,
-0,0,0,0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,8,
-0,0,0,0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,16,
-8,0,0,0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211,
-107,200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39,
-49,224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1,
-241,13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72,
-1,246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213,
-146,138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58,
-217,233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34,
-139,137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232,
-73,69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36,
-162,145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78,
-132,148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117,
-179,232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232,
-73,69,172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216,
-166,210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137,
-147,180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100,
-166,211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35,
-173,158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166,
-209,70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122,
-122,93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100,
-225,86,224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27,
-104,162,100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250,
-178,83,136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207,
-171,37,56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0,
-133,66,215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100,
-1,100,180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26,
-110,255,80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52,
-221,254,64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12,
-50,9,195,39,196,80,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,1,255,
+224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
+136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
+2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
+130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
+138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
+190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
+53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
+124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
+116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
+240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
+51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
+105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
+117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
+65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
+39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
+58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
+133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
+39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
+18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
+194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
+32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
+151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
+214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
+10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
+52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,127,239,255,255,255,255,
+255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,0,0,0,57,136,15,255,0,0,0,0,0,
+0,4,122,247,73,19,69,73,180,134,149,13,68,241,1,255,192,0,0,0,0,0,0,143,90,
+67,2,104,169,54,144,210,161,168,158,32,127,248,0,0,0,0,0,0,14,73,78,20,0,0,
+0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,13,
+155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,222,
+17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,112,
+164,63,252,0,0,0,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,53,224,
+65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,22,78,
+12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,113,67,
+77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,97,47,
+128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,190,
+96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,206,
+185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,76,
+150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,39,
+195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,39,
+198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,163,
+18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,100,40,
+15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,11,90,
+36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,157,160,
+3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,178,166,
+74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,9,205,
+28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,49,13,
+164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,34,79,
+135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,137,62,
+12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,199,54,
+103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,147,225,
+104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,54,223,
+224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,7,38,
+193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,89,
+252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,131,
+64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,231,
+197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,228,
+74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,235,1,
+64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,64,
+174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,168,
+167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,19,
+177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,32,105,221,0,0,0,0,0,91,60,
+149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,110,
+20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,36,14,
+100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,139,
+163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,28,1,
+204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,92,
+203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,100,
+73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,69,
+49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,68,
+152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,49,
+39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,98,
+79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,249,
+68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,136,
+108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,16,
+217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,194,
+173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,89,24,
+70,206,1,255,128,0,0,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,68,89,
+24,70,206,1,255,128,0,0,0,0,0,1,153,51,136,71,161,196,201,45,167,146,59,68,
+89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,168,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,200,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,232,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,8,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,40,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,72,71,161,196,201,45,167,146,59,
+68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,103,
+177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,
+20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,
+183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,
+235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,
+138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,
+37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,
+146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,
+58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,
+207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,
+161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,
+98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,
+209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,
+155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,
+142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,
+155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,
+233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,
+137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,
+156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,
+179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,
+100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,102,
+53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,72,
+16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,32,2,
+223,133,69,138,43,180,132,234,219,163,161,1,0,9,174,198,238,213,84,88,31,
+86,221,40,7,252,197,200,95,223,71,61,225,122,183,27,72,144,15,253,197,81,
+217,74,224,191,131,117,110,54,142,129,32,31,237,229,189,138,147,114,135,2,
+235,209,1,0,36,135,237,81,16,180,96,63,101,8,207,71,107,74,1,255,53,4,243,
+51,249,222,104,94,202,17,158,148,3,255,106,9,230,103,243,188,210,159,129,
+228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,192,25,
+106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,27,165,
+171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,32,24,
+157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,188,8,
+134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,13,65,
+74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,72,1,
+98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,81,
+129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,153,
+78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,128,0,
+10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,164,237,
+35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,120,96,
+196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,16,113,
+137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,100,108,
+144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,108,185,
+36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,10,4,28,
+200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,138,89,
+18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,80,17,42,
+4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,48,141,156,
+3,255,0,0,0,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,178,48,141,
+156,3,255,0,0,0,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,122,192,134,
+241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,69,145,132,
+108,224,31,248,0,0,0,0,0,0,25,140,72,132,122,28,76,146,218,121,35,180,69,
+145,132,108,224,32,0,0,0,0,0,0,0,25,140,80,132,122,28,76,146,218,121,35,
+180,69,145,132,108,224,32,0,0,0,0,0,0,0,25,140,88,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,96,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,104,132,122,28,
+76,146,218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,112,132,
+122,28,76,146,218,121,35,180,69,145,132,108,224,32,16,0,0,0,0,0,0,16,113,
+225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,104,
+82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,165,
+1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,154,
+102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,147,
+161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#elif defined(DUK_USE_DOUBLE_ME)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3819] = {
-144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191,
-135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196,
-52,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26,
-98,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212,
-132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78,
-18,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,232,59,
-147,60,93,110,79,15,39,9,24,186,33,13,63,111,185,16,211,206,251,114,98,17,
-171,160,11,199,197,215,196,66,26,102,38,68,53,212,77,136,104,255,5,114,120,
-121,7,192,70,32,192,67,95,249,59,13,13,127,228,248,134,191,242,133,208,215,
-254,81,204,67,95,249,75,33,13,127,229,61,84,53,255,149,52,80,215,254,85,
-217,67,95,249,91,121,13,90,181,168,134,143,152,95,38,75,207,132,104,156,50,
-70,33,163,225,66,249,50,94,124,25,4,225,146,49,14,24,28,196,0,0,15,135,240,
-0,0,0,12,204,0,0,15,7,240,0,0,0,12,188,72,6,176,77,225,28,24,103,14,33,197,
-138,113,227,28,152,231,46,65,205,19,194,84,11,225,35,23,68,231,138,228,64,
-211,19,132,140,93,19,162,59,145,33,73,18,52,68,225,35,23,68,233,139,228,
-176,217,130,252,36,98,232,157,81,60,158,30,78,18,49,116,78,184,142,210,40,
-39,99,23,68,236,201,59,114,142,224,126,14,138,152,30,67,188,23,143,139,175,
-131,194,135,228,72,85,144,83,60,53,163,208,76,60,68,211,197,78,60,116,243,
-200,80,60,149,19,202,82,60,181,51,204,84,60,213,83,206,86,60,240,190,76,
-151,159,8,209,56,100,137,232,133,242,100,188,248,50,9,195,36,79,73,26,238,
-108,129,15,4,100,78,33,179,207,160,41,224,140,137,194,173,192,158,120,128,
-168,151,26,14,55,58,64,132,75,133,67,81,50,103,8,18,50,9,195,39,105,20,101,
-136,36,50,9,195,39,105,20,11,174,99,220,210,54,121,114,4,145,162,112,201,
-218,69,25,130,9,17,162,112,201,218,69,2,235,152,247,52,141,158,100,128,196,
-144,128,242,102,136,17,70,146,66,3,201,160,32,0,130,225,48,113,137,62,62,
-46,155,167,135,147,142,47,24,147,79,205,68,48,98,79,142,179,120,248,185,
-228,140,241,193,146,66,138,31,55,71,126,129,51,18,124,117,155,199,197,207,
-36,103,142,52,12,36,184,100,129,129,41,32,205,221,175,3,10,36,4,201,188,64,
-112,200,84,52,156,124,92,242,70,120,223,48,64,100,42,26,78,62,46,121,35,52,
-18,91,212,2,72,128,95,20,128,197,137,9,146,113,73,8,190,36,169,27,62,18,
-243,35,100,135,54,92,66,4,34,92,145,0,178,15,132,64,132,75,133,139,178,70,
-240,137,6,34,92,37,230,70,201,1,89,56,36,4,81,49,46,25,5,76,73,241,214,111,
-31,23,60,145,158,57,44,48,46,92,184,100,160,145,46,2,0,201,168,207,198,230,
-144,117,60,176,48,156,160,48,188,192,7,28,18,227,172,222,62,46,121,35,60,
-113,200,26,137,113,241,116,221,60,60,156,113,121,4,20,124,92,242,70,120,
-226,37,194,54,140,36,64,21,147,146,68,24,32,57,0,125,78,84,0,160,123,215,
-140,146,1,4,5,175,40,124,8,20,52,121,51,228,24,96,129,209,46,2,49,6,20,135,
-33,20,53,50,128,194,65,4,12,39,52,64,155,31,48,112,72,6,247,62,16,1,31,73,
-30,25,240,60,73,82,70,68,138,0,89,29,5,156,96,2,201,104,17,35,160,18,78,
-140,228,16,26,79,90,4,73,43,192,244,108,142,130,206,89,240,58,26,50,95,142,
-43,159,65,107,4,167,196,52,100,191,28,87,63,128,15,255,240,164,169,35,136,
-6,128,146,115,9,0,210,7,43,163,194,0,71,128,105,65,176,15,128,105,131,21,
-11,153,35,0,211,134,137,7,65,18,33,244,23,18,14,130,39,34,131,30,113,15,
-224,3,255,254,12,80,81,133,139,153,193,28,17,224,156,50,119,15,131,75,23,
-51,130,112,201,199,185,13,159,116,248,228,68,219,66,149,83,83,238,3,11,238,
-0,48,142,8,240,19,239,144,40,71,4,120,39,12,156,4,252,4,11,19,134,78,61,
-200,108,248,9,248,9,3,9,205,16,39,225,62,7,67,70,75,241,197,241,154,5,172,
-18,159,16,209,146,252,113,124,102,144,106,220,32,44,156,19,152,240,68,158,
-66,2,176,19,17,252,164,7,137,30,176,8,158,116,3,72,128,136,143,232,32,44,
-150,129,19,210,128,89,61,104,159,169,1,50,160,101,56,161,166,246,160,46,
-110,226,221,98,71,130,4,137,222,0,140,221,197,184,64,89,56,183,88,145,224,
-129,34,119,128,23,55,114,143,121,35,193,2,68,239,2,17,155,184,183,8,11,39,
-40,247,146,60,16,36,78,240,32,73,197,12,247,128,26,36,121,1,63,49,2,165,48,
-70,114,229,145,51,250,205,2,8,209,203,150,68,207,235,52,130,16,209,46,131,
-36,188,70,128,210,160,101,56,251,16,131,28,7,35,38,218,50,234,103,130,97,
-103,129,6,73,0,79,88,11,237,84,11,161,32,127,255,247,191,255,255,255,255,
-137,235,16,221,170,129,116,36,0,0,0,0,0,16,0,0,12,196,0,0,15,135,240,0,0,0,
-2,61,123,164,137,162,164,218,67,74,134,162,120,128,0,1,224,254,0,0,0,0,71,
-173,33,129,52,84,155,72,105,80,212,79,16,0,0,60,63,192,0,0,0,7,36,38,218,0,
-0,0,0,0,0,0,0,4,29,78,224,140,38,216,140,46,228,0,243,119,10,139,144,123,
-82,6,205,220,37,222,230,145,179,64,23,180,32,92,221,199,196,130,68,144,230,
-237,200,131,44,24,43,193,25,18,185,0,251,73,138,199,240,27,93,106,192,57,
-41,54,210,0,0,62,31,192,0,0,0,49,58,155,192,12,155,184,48,76,156,148,226,
-134,154,240,32,201,187,147,67,9,201,78,40,105,175,2,225,47,3,18,155,184,
-183,8,11,39,6,9,147,146,156,80,211,94,7,37,55,113,110,16,22,78,77,12,39,37,
-56,161,166,188,16,48,215,130,14,30,240,66,213,93,35,11,124,0,230,36,249,52,
-48,151,192,22,98,79,133,162,215,204,16,17,178,16,199,24,147,237,38,34,246,
-139,95,48,64,70,200,68,16,98,79,140,115,102,123,33,20,89,137,62,210,98,103,
-92,217,158,200,70,14,98,79,131,4,201,100,35,138,49,39,218,76,67,232,38,75,
-33,32,49,137,62,12,24,178,18,68,152,147,237,38,33,244,24,178,18,132,24,147,
-225,221,72,202,200,75,22,98,79,180,152,143,215,82,50,178,19,5,24,147,227,
-16,218,76,146,178,19,70,152,147,237,38,38,117,13,164,201,43,33,56,81,137,
-62,72,130,115,71,43,33,60,105,137,62,210,98,151,72,39,52,114,178,20,7,152,
-147,227,16,181,162,68,19,154,57,89,10,36,140,73,246,147,19,58,133,173,18,
-32,156,209,202,200,82,34,98,79,147,67,9,151,52,156,113,75,34,78,208,1,228,
-73,242,104,97,46,16,62,68,159,24,133,173,18,32,156,209,202,217,83,37,34,79,
-180,152,153,212,45,104,145,4,230,142,86,202,160,169,18,124,145,4,230,142,
-86,215,213,27,34,79,180,152,165,210,9,205,28,173,175,172,42,68,159,24,134,
-210,100,149,183,245,198,200,147,237,38,38,117,13,164,201,43,111,236,8,145,
-39,195,186,145,149,185,246,69,200,147,237,38,35,245,212,140,173,207,180,30,
-68,159,6,9,146,217,91,21,34,79,180,152,135,208,76,150,202,224,137,18,124,
-99,155,51,219,95,116,92,137,62,210,98,103,92,217,158,218,251,194,228,73,
-240,180,90,249,130,2,54,223,223,29,34,79,180,152,139,218,45,124,193,1,27,
-111,240,33,204,73,243,4,4,108,134,8,60,137,62,96,128,141,178,193,193,154,3,
-147,32,227,36,0,0,0,0,0,0,0,0,99,115,245,195,19,159,176,75,175,159,176,24,
-172,253,129,49,121,251,2,176,66,92,130,235,16,18,100,148,251,36,106,123,64,
-65,158,3,147,160,108,202,62,68,165,107,243,227,113,198,211,62,39,20,108,
-115,226,241,130,106,113,224,78,162,4,242,130,236,197,60,37,64,190,18,49,
-116,114,37,40,157,76,9,229,37,217,138,185,16,52,196,225,35,23,71,34,82,137,
-213,64,158,84,93,152,187,145,33,73,18,52,68,225,35,23,71,34,82,137,213,192,
-158,86,93,152,175,146,195,102,11,240,145,139,163,145,41,68,235,32,79,44,46,
-204,83,201,225,228,225,35,23,71,34,82,137,214,192,158,90,93,152,163,180,
-138,9,216,197,209,200,148,161,194,32,30,18,0,85,248,42,3,74,184,164,88,78,
-173,186,58,16,44,90,192,144,5,149,109,110,193,245,109,210,128,132,93,204,
-127,222,115,245,252,23,171,113,180,137,1,28,87,220,255,250,8,173,148,55,86,
-227,104,232,18,3,222,94,217,248,119,41,48,168,46,189,16,62,200,66,80,6,11,
-81,21,3,246,80,140,244,118,180,160,79,80,115,31,230,157,191,179,5,236,161,
-25,233,64,158,160,246,63,205,59,127,102,41,248,30,75,12,11,151,242,233,187,
-146,156,80,211,114,96,54,230,41,20,129,128,50,211,16,16,2,116,180,196,129,
-1,36,55,76,74,16,19,3,116,196,193,65,48,55,75,80,128,65,6,51,211,20,128,
-130,34,23,166,39,6,39,75,76,80,1,146,239,211,20,16,165,91,157,29,49,66,10,
-124,61,211,209,175,1,173,198,211,20,48,139,113,180,180,197,36,42,220,109,
-29,13,49,74,6,192,95,72,188,6,196,55,74,188,6,247,91,80,136,26,32,104,220,
-205,56,1,98,234,52,122,98,136,14,72,110,152,162,132,148,35,61,49,70,7,48,
-55,76,81,194,206,52,104,180,197,45,192,80,175,4,100,77,10,2,101,56,161,166,
-65,113,162,98,8,3,131,7,169,35,36,57,176,0,40,116,208,0,0,0,0,45,158,10,
-225,223,132,17,13,43,176,228,3,0,167,129,32,17,133,134,32,25,80,220,40,240,
-25,26,44,32,240,24,200,44,24,240,56,156,199,128,83,193,17,7,4,13,128,0,10,
-79,202,28,223,195,1,197,72,196,141,159,220,7,48,33,7,8,3,152,49,117,60,240,
-76,47,60,9,224,187,56,43,224,221,64,172,156,36,98,232,228,96,220,145,139,
-163,182,134,237,146,49,116,118,206,6,141,104,105,136,32,14,4,128,160,123,
-215,140,147,32,145,57,178,156,104,41,228,151,168,225,144,168,105,56,248,
-185,228,140,241,190,100,209,244,80,210,116,151,134,12,73,241,214,111,31,23,
-60,145,158,56,50,72,81,67,230,232,239,209,7,24,147,227,226,233,186,120,121,
-56,226,241,137,116,189,52,6,34,92,37,230,70,201,1,89,56,36,154,110,25,49,
-23,196,149,35,103,194,94,100,108,144,230,203,136,73,174,234,63,52,252,212,
-87,0,131,138,4,12,137,114,168,37,166,144,230,37,5,7,19,39,22,70,154,103,
-143,252,4,11,37,160,68,164,139,7,24,3,152,182,20,28,76,156,89,26,105,158,
-63,240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,132,176,230,
-36,248,134,207,98,138,99,4,24,147,229,16,217,236,81,75,98,12,73,241,13,158,
-142,181,20,198,137,49,39,202,33,179,209,214,162,151,4,24,147,226,27,61,61,
-42,41,142,18,98,79,148,67,103,167,165,69,46,138,49,39,194,173,192,158,158,
-149,20,188,40,196,159,10,183,2,122,218,148,82,248,121,18,124,67,103,177,77,
-177,130,36,73,242,136,108,246,41,181,177,18,36,248,134,207,71,90,155,99,68,
-200,147,229,16,217,232,235,83,107,130,36,73,241,13,158,158,149,54,199,9,
-145,39,202,33,179,211,210,166,215,69,72,147,225,86,224,79,79,74,155,94,21,
-34,79,133,91,129,61,109,74,109,126,14,56,7,6,20,28,76,156,89,26,105,158,63,
-240,5,7,19,39,28,82,200,147,143,253,0,193,161,74,72,199,253,130,235,191,
-232,8,149,2,8,196,24,164,137,141,200,8,71,161,196,201,45,167,146,59,68,89,
-24,70,206,0,0,7,129,248,0,0,0,1,142,49,232,71,161,196,201,45,167,146,59,68,
-89,24,70,206,0,0,7,129,248,0,0,0,1,141,201,8,71,161,196,201,45,167,146,59,
-68,89,24,70,206,0,0,7,129,248,0,0,0,2,138,2,214,225,113,235,2,27,128,0,10,
-66,3,189,96,67,120,226,224,0,2,148,140,113,145,66,61,14,38,73,109,60,145,
-218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,80,66,61,14,38,73,109,60,
-145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,113,147,66,61,14,38,73,
-109,60,145,218,34,200,194,54,112,0,0,60,15,192,0,0,0,12,110,88,66,61,14,38,
-73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,149,66,61,14,
-38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,96,66,61,14,
-38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,113,151,66,61,
-14,38,73,109,60,145,218,34,200,194,54,112,0,0,0,16,0,0,0,0,12,110,104,66,
-61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,113,153,
-66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,110,
-112,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,12,
-113,155,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,0,
-12,110,120,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,0,
-0,12,113,157,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,4,16,0,0,
-0,0,12,110,128,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16,0,
-0,0,0,12,113,159,66,61,14,38,73,109,60,145,218,34,200,194,54,112,0,0,8,16,
-0,0,0,0,8,58,32,128,24,78,104,129,61,82,2,145,46,17,162,112,208,211,107,
-200,16,137,112,52,41,73,29,113,2,131,137,147,139,35,77,51,234,80,14,39,49,
-224,137,40,35,100,141,9,136,19,18,0,125,162,58,217,236,81,64,68,72,1,241,
-13,158,197,20,150,50,36,0,251,68,117,179,209,214,234,201,69,16,100,72,1,
-246,136,235,103,163,173,208,146,138,68,23,18,0,124,67,103,163,173,213,146,
-138,76,23,18,0,124,67,103,163,173,208,146,138,84,25,18,0,125,162,58,217,
-233,233,117,100,162,138,50,36,0,251,68,117,179,211,210,232,73,69,34,139,
-137,0,62,33,179,211,210,234,201,69,38,139,137,0,62,33,179,211,210,232,73,
-69,42,139,137,0,62,21,110,4,250,178,81,70,23,18,0,124,42,220,9,244,36,162,
-145,134,68,128,31,6,234,5,100,234,201,69,28,100,72,1,240,110,160,86,78,132,
-148,82,56,168,144,3,237,17,214,207,171,37,22,128,42,36,0,251,68,117,179,
-232,73,69,164,9,137,0,62,33,179,234,201,69,168,9,137,0,62,33,179,232,73,69,
-172,10,180,81,50,118,136,235,103,177,77,129,54,138,38,78,33,179,216,166,
-210,198,218,40,153,59,68,117,179,209,214,234,201,77,144,109,162,137,147,
-180,71,91,61,29,110,132,148,218,32,203,69,19,39,16,217,232,235,117,100,166,
-211,6,90,40,153,56,134,207,71,91,161,37,54,168,54,209,68,201,218,35,173,
-158,158,151,86,74,108,163,109,20,76,157,162,58,217,233,233,116,36,166,209,
-70,90,40,153,56,134,207,79,75,171,37,54,154,50,209,68,201,196,54,122,122,
-93,9,41,181,81,150,138,38,78,21,110,4,250,178,83,102,25,104,162,100,225,86,
-224,79,161,37,54,140,54,209,68,201,193,186,129,89,58,178,83,103,27,104,162,
-100,224,221,64,172,157,9,41,180,113,118,138,38,78,209,29,108,250,178,83,
-136,2,237,20,76,157,162,58,217,244,36,167,18,5,90,40,153,56,134,207,171,37,
-56,160,42,209,68,201,196,54,125,9,41,197,141,78,197,141,86,192,0,133,66,
-215,173,96,49,33,64,46,84,8,14,39,49,224,137,40,18,4,19,159,141,100,1,100,
-180,8,148,146,0,91,69,19,38,202,8,58,64,28,209,160,130,52,78,26,26,110,255,
-80,64,196,104,156,50,125,4,144,116,192,57,165,97,4,104,156,52,52,221,254,
-64,20,160,152,23,223,228,32,148,25,174,137,58,23,51,191,200,84,12,50,9,195,
-39,196,80,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
+144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
+252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
+64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
+142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
+242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
+1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
+13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
+0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
+0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
+217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
+146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,3,
+225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
+136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
+2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
+130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
+138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
+190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
+53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
+124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
+116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
+240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
+51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
+105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
+117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
+65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
+39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
+58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
+133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
+39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
+18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
+194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
+32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
+151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
+214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
+10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
+52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
+214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
+165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
+143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
+180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
+54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
+178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
+129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
+201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
+132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
+46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
+193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
+133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
+9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
+134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
+64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
+145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
+77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
+110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
+110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
+127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
+33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
+4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,239,127,255,255,
+255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,32,0,0,25,136,0,0,31,15,224,0,
+0,0,4,122,247,73,19,69,73,180,134,149,13,68,241,0,0,3,193,252,0,0,0,0,143,
+90,67,2,104,169,54,144,210,161,168,158,32,0,0,120,127,128,0,0,0,14,73,78,
+20,0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,
+68,13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
+222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
+112,164,0,0,124,63,128,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,
+53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
+22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
+113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
+97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
+190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
+206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
+76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
+39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
+39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
+163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
+100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
+11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
+157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
+178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
+9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
+49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
+34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
+137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
+199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
+147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
+54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
+7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
+89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
+131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
+231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
+228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
+235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
+64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
+168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
+19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,93,105,160,0,0,0,0,91,
+60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,
+110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,
+36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,
+139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,
+28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,
+92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,
+100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,
+69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,
+68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,
+49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
+98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
+249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
+136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
+16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
+194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
+89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,
+68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,136,71,161,196,201,45,167,146,
+59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,168,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,200,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,232,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,8,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,40,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,72,71,161,196,201,45,167,
+146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,
+103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
+171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
+158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
+246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
+37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
+75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
+39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
+129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
+17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
+207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
+207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
+78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
+146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
+104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
+146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
+217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
+162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
+77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
+117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
+162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
+102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
+72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,5,
+95,130,160,52,171,138,69,132,234,219,163,161,2,197,172,9,0,89,86,214,236,
+31,86,221,40,8,69,220,199,253,231,63,95,193,122,183,27,72,144,17,197,125,
+207,255,160,138,217,67,117,110,54,142,129,32,61,229,237,159,135,114,147,10,
+130,235,209,3,236,132,37,0,96,181,17,80,63,101,8,207,71,107,74,4,245,7,49,
+254,105,219,251,48,94,202,17,158,148,9,234,15,99,252,211,183,246,98,159,
+129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
+192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
+27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
+32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
+188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
+13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
+72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
+81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
+153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
+128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
+164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
+120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
+16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
+100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
+108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
+10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
+138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
+80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
+48,141,156,0,0,15,3,240,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,
+178,48,141,156,0,0,15,3,240,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,
+122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,120,31,128,0,0,0,25,140,72,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,80,132,122,28,76,146,
+218,121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,88,132,122,28,76,
+146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,96,132,122,
+28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,104,
+132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,
+140,112,132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,16,32,0,0,
+0,0,16,113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,
+18,224,104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,
+70,131,165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,
+7,78,3,154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,
+232,147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
};
#else
#error invalid endianness defines
@@ -11004,12 +11381,12 @@ DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t
#if defined(DUK_USE_PARANOID_ERRORS)
DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_get_type_name((duk_context *) thr, idx), (long) idx);
+ expect_name, duk_get_type_name(thr, idx), (long) idx);
}
#else
DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_push_string_readable((duk_context *) thr, idx), (long) idx);
+ expect_name, duk_push_string_readable(thr, idx), (long) idx);
}
#endif
DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
@@ -11044,8 +11421,8 @@ DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, co
* when non-verbose errors are used.
*/
-DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_uint_t code));
-DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_uint_t code) {
+DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code));
+DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) {
DUK_ERROR_RAW(thr, NULL, 0, code, NULL);
}
DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) {
@@ -11087,6 +11464,17 @@ DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *ms
/* Default behavior is to abort() on error. There's no printout
* which makes this awkward, so it's always recommended to use an
* explicit fatal error handler.
+ *
+ * ====================================================================
+ * NOTE: If you are seeing this, you are most likely dealing with an
+ * uncaught error. You should provide a fatal error handler in Duktape
+ * heap creation, and should consider using a protected call as your
+ * first call into an empty Duktape context to properly handle errors.
+ * See:
+ * - http://duktape.org/guide.html#error-handling
+ * - http://wiki.duktape.org/HowtoFatalErrors.html
+ * - http://duktape.org/api.html#taglist-protected
+ * ====================================================================
*/
DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL"));
DUK_ABORT();
@@ -11928,8 +12316,8 @@ duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
duk_codepoint_t start_i;
duk_codepoint_t start_o;
- DUK_UNREF(thr);
DUK_ASSERT(bd_ctx != NULL);
+ DUK_UNREF(thr);
DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
@@ -12111,15 +12499,14 @@ duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
* Replace valstack top with case converted version.
*/
-DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase) {
duk_hstring *h_input;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t prev, curr, next;
- h_input = duk_require_hstring(ctx, -1); /* Accept symbols. */
+ h_input = duk_require_hstring(thr, -1); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
@@ -12166,9 +12553,9 @@ DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_in
}
DUK_BW_COMPACT(thr, bw);
- (void) duk_buffer_to_string(ctx, -1); /* Safe, output is encoded. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe, output is encoded. */
/* invalidates h_buf pointer */
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
}
#if defined(DUK_USE_REGEXP_SUPPORT)
@@ -12597,9 +12984,9 @@ DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
*/
#if defined(DUK_USE_64BIT_OPS)
#if defined(DUK_USE_DOUBLE_ME)
- return (du.ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL;
+ return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000);
#else
- return (du.ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL;
+ return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000);
#endif
#else
return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
@@ -12616,21 +13003,21 @@ DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
du.d = x;
#if defined(DUK_USE_64BIT_OPS)
#if defined(DUK_USE_DOUBLE_ME)
- t = du.ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL;
- if (t == 0x0000000000000000ULL) {
- t = du.ull[DUK_DBL_IDX_ULL0] & 0x0000000080000000ULL;
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000);
+ if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000);
return t == 0;
}
- if (t == 0x000000007ff00000UL) {
+ if (t == DUK_U64_CONSTANT(0x000000007ff00000)) {
return 1;
}
#else
- t = du.ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL;
- if (t == 0x0000000000000000ULL) {
- t = du.ull[DUK_DBL_IDX_ULL0] & 0x8000000000000000ULL;
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000);
+ if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
+ t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000);
return t == 0;
}
- if (t == 0x7ff0000000000000ULL) {
+ if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) {
return 1;
}
#endif
@@ -12654,7 +13041,7 @@ DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
/* XXX: optimize */
- duk_small_int_t s = duk_double_signbit(x);
+ duk_small_uint_t s = duk_double_signbit(x);
x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
if (s) {
x = -x;
@@ -12857,13 +13244,12 @@ DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) {
duk_hbuffer_dynamic *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, idx);
+ h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
@@ -12876,15 +13262,14 @@ DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t
return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
}
-DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
duk_hbuffer_dynamic *h;
void *ptr;
duk_size_t sz;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, idx);
+ h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
@@ -12907,13 +13292,12 @@ DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t
return ptr;
}
-DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) {
duk_hbuffer_external *h;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, idx);
+ h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
@@ -12940,31 +13324,31 @@ DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr,
#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-#define DUK__SER_MARKER 0xff
-#define DUK__SER_VERSION 0x00
+#define DUK__SER_MARKER 0xbf
#define DUK__SER_STRING 0x00
#define DUK__SER_NUMBER 0x01
#define DUK__BYTECODE_INITIAL_ALLOC 256
+#define DUK__NO_FORMALS 0xffffffffUL
/*
* Dump/load helpers, xxx_raw() helpers do no buffer checks
*/
-DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) {
+DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_hthread *thr, duk_uint8_t *p) {
duk_uint32_t len;
len = DUK_RAW_READ_U32_BE(p);
- duk_push_lstring(ctx, (const char *) p, len);
+ duk_push_lstring(thr, (const char *) p, len);
p += len;
return p;
}
-DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) {
+DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, duk_uint8_t *p) {
duk_uint32_t len;
duk_uint8_t *buf;
len = DUK_RAW_READ_U32_BE(p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);
DUK_ASSERT(buf != NULL);
DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
p += len;
@@ -13020,7 +13404,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, d
DUK_ASSERT(h_str != NULL);
}
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
p = duk__dump_hstring_raw(p, h_str);
return p;
}
@@ -13034,10 +13418,10 @@ DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, d
h_buf = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h_buf != NULL);
DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p);
p = duk__dump_hbuffer_raw(thr, p, h_buf);
} else {
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, 0);
}
return p;
@@ -13053,7 +13437,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, d
} else {
val = def_value;
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, val);
return p;
}
@@ -13094,12 +13478,12 @@ DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bu
#endif
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p);
p = duk__dump_hstring_raw(p, key);
DUK_RAW_WRITE_U32_BE(p, val);
}
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */
return p;
}
@@ -13109,45 +13493,48 @@ DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_b
tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_uint_fast32_t i;
+ duk_harray *h;
+ duk_uint32_t i;
- h = DUK_TVAL_GET_OBJECT(tv);
+ /* Here we rely on _Formals being a dense array containing
+ * strings. This should be the case unless _Formals has been
+ * tweaked by the application (which we don't support right
+ * now).
+ */
+ h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
+ DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h));
- /* We know _Formals is dense and all entries will be in the
- * array part. GC and finalizers shouldn't affect _Formals
- * so side effects should be fine.
- */
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
+ DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */
+ DUK_RAW_WRITE_U32_BE(p, h->length);
+
+ for (i = 0; i < h->length; i++) {
duk_tval *tv_val;
duk_hstring *varname;
- tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
+ tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
DUK_ASSERT(tv_val != NULL);
- if (DUK_TVAL_IS_STRING(tv_val)) {
- /* Array is dense and contains only strings, but ASIZE may
- * be larger than used part and there are UNUSED entries.
- */
- varname = DUK_TVAL_GET_STRING(tv_val);
- DUK_ASSERT(varname != NULL);
- DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); /* won't be confused with terminator */
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
- DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
- p = duk__dump_hstring_raw(p, varname);
- }
+ varname = DUK_TVAL_GET_STRING(tv_val);
+ DUK_ASSERT(varname != NULL);
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
+
+ DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p);
+ p = duk__dump_hstring_raw(p, varname);
}
} else {
- DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit empty list"));
+ DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
+ DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */
}
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
- DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
return p;
}
-static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
- duk_hthread *thr;
+static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
duk_tval *tv, *tv_end;
duk_instr_t *ins, *ins_end;
duk_hobject **fn, **fn_end;
@@ -13157,10 +13544,6 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bu
duk_uint16_t tmp16;
duk_double_t d;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
- DUK_UNREF(thr);
-
DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
"consts=[%p,%p[ (%ld bytes, %ld items), "
"funcs=[%p,%p[ (%ld bytes, %ld items), "
@@ -13182,7 +13565,7 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bu
DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func);
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p);
/* Fixed header info. */
tmp32 = count_instr;
@@ -13237,12 +13620,12 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bu
h_str = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h_str != NULL);
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p),
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p),
*p++ = DUK__SER_STRING;
p = duk__dump_hstring_raw(p, h_str);
} else {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p);
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p);
*p++ = DUK__SER_NUMBER;
d = DUK_TVAL_GET_NUMBER(tv);
DUK_RAW_WRITE_DOUBLE_BE(p, d);
@@ -13261,7 +13644,7 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bu
* to serialize deep functions.
*/
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn));
- p = duk__dump_func(ctx, (duk_hcompfunc *) *fn, bw_ctx, p);
+ p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p);
fn++;
}
@@ -13306,8 +13689,7 @@ static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bu
DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
} while (0)
-static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) {
- duk_hthread *thr;
+static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t *p_end) {
duk_hcompfunc *h_fun;
duk_hbuffer *h_data;
duk_size_t data_size;
@@ -13320,6 +13702,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
duk_idx_t idx_base;
duk_tval *tv1;
duk_uarridx_t arr_idx;
+ duk_uarridx_t arr_limit;
duk_hobject *func_env;
duk_bool_t need_pop;
@@ -13328,8 +13711,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
* looks the same as created by duk_js_closure().
*/
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(thr != NULL);
DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
@@ -13350,13 +13732,13 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
* inner functions being loaded. Require enough space to handle
* large functions correctly.
*/
- duk_require_stack(ctx, 2 + count_const + count_funcs);
- idx_base = duk_get_top(ctx);
+ duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs));
+ idx_base = duk_get_top(thr);
/* Push function object, init flags etc. This must match
* duk_js_push_closure() quite carefully.
*/
- h_fun = duk_push_hcompfunc(ctx);
+ h_fun = duk_push_hcompfunc(thr);
DUK_ASSERT(h_fun != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun));
DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL);
@@ -13377,8 +13759,11 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
tmp32 = DUK_RAW_READ_U32_BE(p);
DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */
- /* standard prototype */
+ /* standard prototype (no need to set here, already set) */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#if 0
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#endif
/* assert just a few critical flags */
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
@@ -13391,7 +13776,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
/* Create function 'data' buffer but don't attach it yet. */
- fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, data_size);
+ fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size);
DUK_ASSERT(fun_data != NULL);
/* Load bytecode instructions. */
@@ -13417,7 +13802,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
const_type = DUK_RAW_READ_U8(p);
switch (const_type) {
case DUK__SER_STRING: {
- p = duk__load_string_raw(ctx, p);
+ p = duk__load_string_raw(thr, p);
break;
}
case DUK__SER_NUMBER: {
@@ -13429,7 +13814,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
DUK__ASSERT_LEFT(8);
val = DUK_RAW_READ_DOUBLE_BE(p);
DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val);
- duk_push_tval(ctx, &tv_tmp);
+ duk_push_tval(thr, &tv_tmp);
break;
}
default: {
@@ -13440,7 +13825,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
/* Load inner functions to value stack, but don't yet copy to buffer. */
for (n = count_funcs; n > 0; n--) {
- p = duk__load_func(ctx, p, p_end);
+ p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
@@ -13455,12 +13840,12 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
* them afterwards.
*/
- h_data = (duk_hbuffer *) duk_known_hbuffer(ctx, idx_base + 1);
+ h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1);
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data);
DUK_HBUFFER_INCREF(thr, h_data);
- tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */
+ tv1 = duk_get_tval(thr, idx_base + 2); /* may be NULL if no constants or inner funcs */
DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
q = fun_data;
@@ -13493,16 +13878,16 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
/* The function object is now reachable and refcounts are fine,
* so we can pop off all the temporaries.
*/
- DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base)));
- duk_set_top(ctx, idx_base + 1);
+ DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(thr, idx_base)));
+ duk_set_top(thr, idx_base + 1);
/* Setup function properties. */
tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
+ duk_push_u32(thr, tmp32);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
#if defined(DUK_USE_FUNC_NAME_PROPERTY)
- p = duk__load_string_raw(ctx, p); /* -> [ func funcname ] */
+ p = duk__load_string_raw(thr, p); /* -> [ func funcname ] */
func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
DUK_ASSERT(func_env != NULL);
need_pop = 0;
@@ -13519,7 +13904,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
DUK_ASSERT(new_env != NULL);
DUK_ASSERT(new_env->thread == NULL); /* Closed. */
DUK_ASSERT(new_env->varmap == NULL);
- DUK_ASSERT(new_env->regbase == 0);
+ DUK_ASSERT(new_env->regbase_byteoff == 0);
DUK_ASSERT_HDECENV_VALID(new_env);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env);
@@ -13527,11 +13912,11 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
func_env = (duk_hobject *) new_env;
- duk_push_hobject(ctx, (duk_hobject *) new_env);
+ duk_push_hobject(thr, (duk_hobject *) new_env);
- duk_dup_m2(ctx); /* -> [ func funcname env funcname ] */
- duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
+ duk_dup_m2(thr); /* -> [ func funcname env funcname ] */
+ duk_dup(thr, idx_base); /* -> [ func funcname env funcname func ] */
+ duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */
}
@@ -13541,93 +13926,85 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
DUK_HOBJECT_INCREF(thr, func_env);
DUK_HOBJECT_INCREF(thr, func_env);
if (need_pop) {
- duk_pop(ctx);
+ duk_pop(thr);
}
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
#endif /* DUK_USE_FUNC_NAME_PROPERTY */
#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
- p = duk__load_string_raw(ctx, p);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
+ p = duk__load_string_raw(thr, p);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */
if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) {
/* Restore empty external .prototype only for constructable
* functions.
*/
- duk_push_object(ctx);
- duk_dup_m2(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
- duk_compact_m1(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
+ duk_push_object(thr);
+ duk_dup_m2(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
}
#if defined(DUK_USE_PC2LINE)
- p = duk__load_buffer_raw(ctx, p);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
+ p = duk__load_buffer_raw(thr, p);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
#endif /* DUK_USE_PC2LINE */
- duk_push_object(ctx); /* _Varmap */
+ duk_push_object(thr); /* _Varmap */
for (;;) {
/* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
+ p = duk__load_string_raw(thr, p);
+ if (duk_get_length(thr, -1) == 0) {
+ duk_pop(thr);
break;
}
tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_put_prop(ctx, -3);
+ duk_push_u32(thr, tmp32);
+ duk_put_prop(thr, -3);
}
- duk_compact_m1(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
- /* If _Formals wasn't present in the original function, the list
- * here will be empty. Same happens if _Formals was present but
- * had zero length. We can omit _Formals from the result if its
- * length is zero and matches nargs.
+ /* _Formals may have been missing in the original function, which is
+ * handled using a marker length.
*/
- duk_push_array(ctx); /* _Formals */
- for (arr_idx = 0; ; arr_idx++) {
- /* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
- break;
+ arr_limit = DUK_RAW_READ_U32_BE(p);
+ if (arr_limit != DUK__NO_FORMALS) {
+ duk_push_array(thr); /* _Formals */
+ for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
+ p = duk__load_string_raw(thr, p);
+ duk_put_prop_index(thr, -2, arr_idx);
}
- duk_put_prop_index(ctx, -2, arr_idx);
- }
- if (arr_idx == 0 && h_fun->nargs == 0) {
- duk_pop(ctx);
+ duk_compact_m1(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
} else {
- duk_compact_m1(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
+ DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
}
/* Return with final function pushed on stack top. */
- DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1)));
- DUK_ASSERT_TOP(ctx, idx_base + 1);
+ DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(thr, -1)));
+ DUK_ASSERT_TOP(thr, idx_base + 1);
return p;
format_error:
return NULL;
}
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
duk_hcompfunc *func;
duk_bufwriter_ctx bw_ctx_alloc;
duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
duk_uint8_t *p;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
/* Bound functions don't have all properties so we'd either need to
* lookup the non-bound target function or reject bound functions.
- * For now, bound functions are rejected.
+ * For now, bound functions are rejected with TypeError.
*/
- func = duk_require_hcompfunc(ctx, -1);
+ func = duk_require_hcompfunc(thr, -1);
DUK_ASSERT(func != NULL);
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj));
@@ -13637,26 +14014,22 @@ DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
p = DUK_BW_GET_PTR(thr, bw_ctx);
*p++ = DUK__SER_MARKER;
- *p++ = DUK__SER_VERSION;
- p = duk__dump_func(ctx, func, bw_ctx, p);
+ p = duk__dump_func(thr, func, bw_ctx, p);
DUK_BW_SET_PTR(thr, bw_ctx, p);
DUK_BW_COMPACT(thr, bw_ctx);
- DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1)));
+ DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(thr, -1)));
- duk_remove_m2(ctx); /* [ ... func buf ] -> [ ... buf ] */
+ duk_remove_m2(thr); /* [ ... func buf ] -> [ ... buf ] */
}
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
duk_uint8_t *p_buf, *p, *p_end;
duk_size_t sz;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
+ p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz);
DUK_ASSERT(p_buf != NULL);
/* The caller is responsible for being sure that bytecode being loaded
@@ -13665,36 +14038,38 @@ DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
* (instruction validation would be quite complex to implement).
*
* This signature check is the only sanity check for detecting
- * accidental invalid inputs. The initial 0xFF byte ensures no
- * ordinary string will be accepted by accident.
+ * accidental invalid inputs. The initial byte ensures no ordinary
+ * string or Symbol will be accepted by accident.
*/
p = p_buf;
p_end = p_buf + sz;
- if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
+ if (sz < 1 || p[0] != DUK__SER_MARKER) {
goto format_error;
}
- p += 2;
+ p++;
- p = duk__load_func(ctx, p, p_end);
+ p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
- duk_remove_m2(ctx); /* [ ... buf func ] -> [ ... func ] */
+ duk_remove_m2(thr); /* [ ... buf func ] -> [ ... func ] */
return;
format_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE);
}
#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
@@ -13702,228 +14077,324 @@ DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
/* automatic undefs */
#undef DUK__ASSERT_LEFT
#undef DUK__BYTECODE_INITIAL_ALLOC
+#undef DUK__NO_FORMALS
#undef DUK__SER_MARKER
#undef DUK__SER_NUMBER
#undef DUK__SER_STRING
-#undef DUK__SER_VERSION
/*
* Calls.
*
- * Protected variants should avoid ever throwing an error.
+ * Protected variants should avoid ever throwing an error. Must be careful
+ * to catch errors related to value stack manipulation and property lookup,
+ * not just the call itself.
+ *
+ * The only exception is when arguments are insane, e.g. nargs/nrets are out
+ * of bounds; in such cases an error is thrown for two reasons. First, we
+ * can't always respect the value stack input/output guarantees in such cases
+ * so the caller would end up with the value stack in an unexpected state.
+ * Second, an attempt to create an error might itself fail (although this
+ * could be avoided by pushing a preallocated object/string or a primitive
+ * value).
*/
/* #include duk_internal.h -> already included */
+/*
+ * Helpers
+ */
+
+struct duk__pcall_prop_args {
+ duk_idx_t obj_idx;
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_prop_args duk__pcall_prop_args;
+
+struct duk__pcall_method_args {
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_method_args duk__pcall_method_args;
+
+struct duk__pcall_args {
+ duk_idx_t nargs;
+ duk_small_uint_t call_flags;
+};
+typedef struct duk__pcall_args duk__pcall_args;
+
+/* Compute and validate idx_func for a certain 'nargs' and 'other'
+ * parameter count (1 or 2, depending on whether 'this' binding is
+ * present).
+ */
+DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
+ duk_idx_t idx_func;
+
+ /* XXX: byte arithmetic? */
+
+ DUK_ASSERT(other >= 0);
+
+ idx_func = duk_get_top(thr) - nargs - other;
+ if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ /* unreachable */
+ }
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ return idx_func;
+}
+
+/* Compute idx_func, assume index will be valid. This is a valid assumption
+ * for protected calls: nargs < 0 is checked explicitly and duk_safe_call()
+ * validates the argument count.
+ */
+DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
+ duk_idx_t idx_func;
+
+ /* XXX: byte arithmetic? */
+
+ DUK_ASSERT(nargs >= 0);
+ DUK_ASSERT(other >= 0);
+
+ idx_func = duk_get_top(thr) - nargs - other;
+ DUK_ASSERT(idx_func >= 0);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ return idx_func;
+}
+
/* Prepare value stack for a method call through an object property.
* May currently throw an error e.g. when getting the property.
*/
-DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(nargs >= 0);
DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld",
- (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(ctx)));
+ (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr)));
/* [... key arg1 ... argN] */
/* duplicate key */
- duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
- duk_get_prop(ctx, normalized_obj_idx);
+ duk_dup(thr, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
+ (void) duk_get_prop(thr, normalized_obj_idx);
+
+ DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) {
+ duk_tval *tv_targ;
+ duk_tval *tv_base;
+ duk_tval *tv_key;
- DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ tv_targ = DUK_GET_TVAL_NEGIDX(thr, -1);
+ tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2);
+ DUK_ASSERT(tv_targ >= thr->valstack_bottom && tv_targ < thr->valstack_top);
+ DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top);
+ DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top);
+
+ duk_call_setup_propcall_error(thr, tv_targ, tv_base, tv_key);
+ }
+#endif
/* [... key arg1 ... argN func] */
- duk_replace(ctx, -nargs - 2);
+ duk_replace(thr, -nargs - 2);
/* [... func arg1 ... argN] */
- duk_dup(ctx, normalized_obj_idx);
- duk_insert(ctx, -nargs - 1);
+ duk_dup(thr, normalized_obj_idx);
+ duk_insert(thr, -nargs - 1);
/* [... func this arg1 ... argN] */
}
-DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 1;
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_TYPE_INVALID_ARGS(thr);
- }
+ idx_func = duk__call_get_idx_func(thr, nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- /* XXX: awkward; we assume there is space for this, overwrite
- * directly instead?
- */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
+ duk_insert_undefined(thr, idx_func + 1);
call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ duk_handle_call_unprotected(thr, idx_func, call_flags);
}
-DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_TYPE_INVALID_ARGS(thr);
- }
+ idx_func = duk__call_get_idx_func(thr, nargs, 2);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ duk_handle_call_unprotected(thr, idx_func, call_flags);
}
-DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) {
+DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
/*
* XXX: if duk_handle_call() took values through indices, this could be
* made much more sensible. However, duk_handle_call() needs to fudge
- * the 'this' and 'func' values to handle bound function chains, which
- * is now done "in-place", so this is not a trivial change.
+ * the 'this' and 'func' values to handle bound functions, which is now
+ * done "in-place", so this is not a trivial change.
*/
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */
+ obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
- duk__call_prop_prep_stack(ctx, obj_idx, nargs);
+ duk__call_prop_prep_stack(thr, obj_idx, nargs);
- duk_call_method(ctx, nargs);
+ duk_call_method(thr, nargs);
}
-DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_uint_t call_flags;
+DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_args *args;
duk_idx_t idx_func;
- duk_int_t rc;
+ duk_int_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
- idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* We can't reliably pop anything here because the stack input
- * shape is incorrect. So we throw an error; if the caller has
- * no catch point for this, a fatal error will occur. Another
- * alternative would be to just return an error. But then the
- * stack would be in an unknown state which might cause some
- * very hard to diagnose problems later on. Also note that even
- * if we did not throw an error here, the underlying call handler
- * might STILL throw an out-of-memory error or some other internal
- * fatal error.
- */
+ args = (duk__pcall_args *) udata;
+ idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+
+ duk_insert_undefined(thr, idx_func + 1);
+
+ ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
+
+ return 1;
+}
+
+DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) {
+ duk__pcall_args args;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
return DUK_EXEC_ERROR; /* unreachable */
}
+ args.call_flags = 0;
- /* awkward; we assume there is space for this */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
+ return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
+}
- call_flags = 0; /* respect reclimit, not constructor */
+DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) {
+ duk__pcall_method_args *args;
+ duk_idx_t idx_func;
+ duk_int_t ret;
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(udata != NULL);
- return rc;
+ args = (duk__pcall_method_args *) udata;
+
+ idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+
+ ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
+
+ return 1;
}
-DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_uint_t call_flags;
- duk_idx_t idx_func;
- duk_int_t rc;
+DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) {
+ duk__pcall_method_args args;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* See comments in duk_pcall(). */
+ args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
return DUK_EXEC_ERROR; /* unreachable */
}
+ args.call_flags = call_flags;
- call_flags = 0; /* respect reclimit, not constructor */
+ return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/);
+}
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) {
+ DUK_ASSERT_API_ENTRY(thr);
- return rc;
+ return duk_pcall_method_flags(thr, nargs, 0);
}
-struct duk__pcall_prop_args {
- duk_idx_t obj_idx;
- duk_idx_t nargs;
-};
-typedef struct duk__pcall_prop_args duk__pcall_prop_args;
-
-DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx, void *udata) {
- duk_idx_t obj_idx;
- duk_idx_t nargs;
+DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) {
duk__pcall_prop_args *args;
+ duk_idx_t obj_idx;
+ duk_int_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(udata != NULL);
args = (duk__pcall_prop_args *) udata;
- obj_idx = args->obj_idx;
- nargs = args->nargs;
- obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */
- duk__call_prop_prep_stack(ctx, obj_idx, nargs);
- duk_call_method(ctx, nargs);
+ obj_idx = duk_require_normalize_index(thr, args->obj_idx); /* make absolute */
+ duk__call_prop_prep_stack(thr, obj_idx, args->nargs);
+
+ ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags);
+ DUK_ASSERT(ret == 0);
+ DUK_UNREF(ret);
return 1;
}
-DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) {
+DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
duk__pcall_prop_args args;
- /*
- * Must be careful to catch errors related to value stack manipulation
- * and property lookup, not just the call itself.
- */
-
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
args.obj_idx = obj_idx;
args.nargs = nargs;
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
+ }
+ args.call_flags = 0;
- /* Inputs: explicit arguments (nargs), +1 for key. If the value stack
- * does not contain enough args, an error is thrown; this matches
- * behavior of the other protected call API functions.
- */
- return duk_safe_call(ctx, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
+ return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
}
-DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- if (duk_get_top(ctx) < nargs || nrets < 0) {
- /* See comments in duk_pcall(). */
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* nargs condition; fail if: top - bottom < nargs
+ * <=> top < bottom + nargs
+ * nrets condition; fail if: end - (top - nargs) < nrets
+ * <=> end - top + nargs < nrets
+ * <=> end + nargs < top + nrets
+ */
+ /* XXX: check for any reserve? */
+
+ if (DUK_UNLIKELY((nargs | nrets) < 0 || /* nargs < 0 || nrets < 0; OR sign bits */
+ thr->valstack_top < thr->valstack_bottom + nargs || /* nargs too large compared to top */
+ thr->valstack_end + nargs < thr->valstack_top + nrets)) { /* nrets too large compared to reserve */
+ DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: "
+ "nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), "
+ "end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)",
+ (long) nargs,
+ (long) nrets,
+ (long) (thr->valstack_top - thr->valstack),
+ (long) (thr->valstack_bottom - thr->valstack),
+ (long) nargs,
+ (long) (thr->valstack_end - thr->valstack),
+ (long) nargs,
+ (long) (thr->valstack_top - thr->valstack),
+ (long) nrets));
DUK_ERROR_TYPE_INVALID_ARGS(thr);
return DUK_EXEC_ERROR; /* unreachable */
}
@@ -13937,248 +14408,53 @@ DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function fu
return rc;
}
-DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
- /*
- * There are two [[Construct]] operations in the specification:
- *
- * - E5 Section 13.2.2: for Function objects
- * - E5 Section 15.3.4.5.2: for "bound" Function objects
- *
- * The chain of bound functions is resolved in Section 15.3.4.5.2,
- * with arguments "piling up" until the [[Construct]] internal
- * method is called on the final, actual Function object. Note
- * that the "prototype" property is looked up *only* from the
- * final object, *before* calling the constructor.
- *
- * Currently we follow the bound function chain here to get the
- * "prototype" property value from the final, non-bound function.
- * However, we let duk_handle_call() handle the argument "piling"
- * when the constructor is called. The bound function chain is
- * thus now processed twice.
- *
- * When constructing new Array instances, an unnecessary object is
- * created and discarded now: the standard [[Construct]] creates an
- * object, and calls the Array constructor. The Array constructor
- * returns an Array instance, which is used as the result value for
- * the "new" operation; the object created before the Array constructor
- * call is discarded.
- *
- * This would be easy to fix, e.g. by knowing that the Array constructor
- * will always create a replacement object and skip creating the fallback
- * object in that case.
- *
- * Note: functions called via "new" need to know they are called as a
- * constructor. For instance, built-in constructors behave differently
- * depending on how they are called.
- */
-
- /* XXX: merge this with duk_js_call.c, as this function implements
- * core semantics (or perhaps merge the two files altogether).
- */
-
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *proto;
- duk_hobject *cons;
- duk_hobject *fallback;
- duk_idx_t idx_cons;
- duk_small_uint_t call_flags;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* [... constructor arg1 ... argN] */
-
- idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
-
- DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
- (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));
-
- /* XXX: code duplication */
-
- /*
- * Figure out the final, non-bound constructor, to get "prototype"
- * property.
- */
-
- duk_dup(ctx, idx_cons);
- for (;;) {
- duk_tval *tv;
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_OBJECT(tv)) {
- cons = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(cons != NULL);
- if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
- /* Checking callability of the immediate target
- * is important, same for constructability.
- * Checking it for functions down the bound
- * function chain is not strictly necessary
- * because .bind() should normally reject them.
- * But it's good to check anyway because it's
- * technically possible to edit the bound function
- * chain via internal keys.
- */
- goto not_constructable;
- }
- if (!DUK_HOBJECT_HAS_BOUNDFUNC(cons)) {
- break;
- }
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- /* Lightfuncs cannot be bound. */
- break;
- } else {
- /* Anything else is not constructable. */
- goto not_constructable;
- }
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */
- duk_remove_m2(ctx); /* -> [... target] */
- }
- DUK_ASSERT(duk_is_callable(ctx, -1));
- DUK_ASSERT(duk_is_lightfunc(ctx, -1) ||
- (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUNDFUNC(duk_get_hobject(ctx, -1))));
-
- /* [... constructor arg1 ... argN final_cons] */
-
- /*
- * Create "fallback" object to be used as the object instance,
- * unless the constructor returns a replacement value.
- * Its internal prototype needs to be set based on "prototype"
- * property of the constructor.
- */
-
- duk_push_object(ctx); /* class Object, extensible */
-
- /* [... constructor arg1 ... argN final_cons fallback] */
-
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_PROTOTYPE);
- proto = duk_get_hobject(ctx, -1);
- if (!proto) {
- DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
- "-> leave standard Object prototype as fallback prototype"));
- } else {
- DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
- "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
- fallback = duk_get_hobject(ctx, -2);
- DUK_ASSERT(fallback != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
- }
- duk_pop(ctx);
-
- /* [... constructor arg1 ... argN final_cons fallback] */
-
- /*
- * Manipulate callstack for the call.
- */
-
- duk_dup_top(ctx);
- duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */
- duk_insert(ctx, idx_cons); /* also stash it before constructor,
- * in case we need it (as the fallback value)
- */
- duk_pop(ctx); /* pop final_cons */
-
-
- /* [... fallback constructor fallback(this) arg1 ... argN];
- * Note: idx_cons points to first 'fallback', not 'constructor'.
- */
-
- DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
- "nargs=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
- (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
- (long) nargs,
- (long) duk_get_top(ctx)));
-
- /*
- * Call the constructor function (called in "constructor mode").
- */
-
- call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- /* [... fallback retval] */
-
- DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /*
- * Determine whether to use the constructor return value as the created
- * object instance or not.
- */
-
- if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT |
- DUK_TYPE_MASK_BUFFER |
- DUK_TYPE_MASK_LIGHTFUNC)) {
- duk_remove_m2(ctx);
- } else {
- duk_pop(ctx);
- }
-
- /*
- * Augment created errors upon creation (not when they are thrown or
- * rethrown). __FILE__ and __LINE__ are not desirable here; the call
- * stack reflects the caller which is correct.
- */
+DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) {
+ duk_idx_t idx_func;
-#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
- duk_hthread_sync_currpc(thr);
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
-#endif
+ DUK_ASSERT_API_ENTRY(thr);
- /* [... retval] */
+ idx_func = duk__call_get_idx_func(thr, nargs, 1);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
- return;
+ duk_push_object(thr); /* default instance; internal proto updated by call handling */
+ duk_insert(thr, idx_func + 1);
- not_constructable:
-#if defined(DUK_USE_VERBOSE_ERRORS)
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(ctx, -1));
-#else
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_readable(ctx, -1));
-#endif
-#else
- DUK_ERROR_TYPE(thr, "not constructable");
-#endif
+ duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT);
}
-DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx, void *udata) {
+DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) {
duk_idx_t nargs;
DUK_ASSERT(udata != NULL);
nargs = *((duk_idx_t *) udata);
- duk_new(ctx, nargs);
+ duk_new(thr, nargs);
return 1;
}
-DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
+DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* For now, just use duk_safe_call() to wrap duk_new(). We can't
- * simply use a protected duk_handle_call() because there's post
- * processing which might throw. It should be possible to ensure
- * the post processing never throws (except in internal errors and
- * out of memory etc which are always allowed) and then remove this
- * wrapper.
+ * simply use a protected duk_handle_call() because pushing the
+ * default instance might throw.
*/
- rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
+ if (DUK_UNLIKELY(nargs < 0)) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return DUK_EXEC_ERROR; /* unreachable */
+ }
+
+ rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
return rc;
}
-DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) {
duk_activation *act;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
act = thr->callstack_curr;
if (act != NULL) {
@@ -14190,14 +14466,15 @@ DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
/* XXX: Make this obsolete by adding a function flag for rejecting a
* non-constructor call automatically?
*/
-DUK_INTERNAL void duk_require_constructor_call(duk_context *ctx) {
- if (!duk_is_constructor_call(ctx)) {
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CONSTRUCT_ONLY);
+DUK_INTERNAL void duk_require_constructor_call(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ if (!duk_is_constructor_call(thr)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY);
}
}
-DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) {
duk_activation *act;
/* For user code this could just return 1 (strict) always
@@ -14209,9 +14486,7 @@ DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
* the internal call sites.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
act = thr->callstack_curr;
if (act != NULL) {
@@ -14226,14 +14501,11 @@ DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
* Duktape/C function magic
*/
-DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) {
duk_activation *act;
duk_hobject *func;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
+ DUK_ASSERT_API_ENTRY(thr);
act = thr->callstack_curr;
if (act) {
@@ -14254,14 +14526,13 @@ DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
return 0;
}
-DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
if (DUK_TVAL_IS_OBJECT(tv)) {
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
@@ -14280,12 +14551,12 @@ DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx) {
return 0;
}
-DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic) {
+DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) {
duk_hnatfunc *nf;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- nf = duk_require_hnatfunc(ctx, idx);
+ nf = duk_require_hnatfunc(thr, idx);
DUK_ASSERT(nf != NULL);
nf->magic = (duk_int16_t) magic;
}
@@ -14294,30 +14565,40 @@ DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic
* Misc helpers
*/
-DUK_INTERNAL void duk_resolve_nonbound_function(duk_context *ctx) {
- duk_uint_t sanity;
+/* Resolve a bound function on value stack top to a non-bound target
+ * (leave other values as is).
+ */
+DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
duk_tval *tv;
- sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
- do {
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
- if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- /* Lightweight function: never bound, so terminate. */
- break;
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *func;
+ DUK_ASSERT_HTHREAD_VALID(thr);
- func = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(func != NULL);
- if (!DUK_HOBJECT_IS_CALLABLE(func) || !DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
- break;
- }
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET);
- duk_replace(ctx, -2);
- } else {
- break;
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
+ duk_push_tval(thr, &((duk_hboundfunc *) h)->target);
+ duk_replace(thr, -2);
+#if 0
+ DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
+ DUK_TVAL_INCREF(thr, tv);
+ DUK_HOBJECT_DECREF_NORZ(thr, h);
+#endif
+ /* Rely on Function.prototype.bind() on never creating a bound
+ * function whose target is not proper. This is now safe
+ * because the target is not even an internal property but a
+ * struct member.
+ */
+ DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1));
}
- } while (--sanity > 0);
+ }
+
+ /* Lightfuncs cannot be bound but are always callable and
+ * constructable.
+ */
}
/*
* Encoding and decoding basic formats: hex, base64.
@@ -14333,21 +14614,21 @@ DUK_INTERNAL void duk_resolve_nonbound_function(duk_context *ctx) {
* 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 idx, duk_size_t *out_len) {
+DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
void *ptr;
duk_bool_t isbuffer;
- DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */
+ DUK_ASSERT(duk_is_valid_index(thr, idx)); /* checked by caller */
/* XXX: with def_ptr set to a stack related pointer, isbuffer could
* be removed from the helper?
*/
- ptr = duk_get_buffer_data_raw(ctx, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer);
+ ptr = duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer);
if (isbuffer) {
DUK_ASSERT(*out_len == 0 || ptr != NULL);
return (const duk_uint8_t *) ptr;
}
- return (const duk_uint8_t *) duk_to_lstring(ctx, idx, out_len);
+ return (const duk_uint8_t *) duk_to_lstring(thr, idx, out_len);
}
#if defined(DUK_USE_BASE64_FASTPATH)
@@ -14696,22 +14977,21 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
}
#endif /* DUK_USE_BASE64_FASTPATH */
-DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
duk_uint8_t *dst;
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: optimize for string inputs: no need to coerce to a buffer
* which makes a copy of the input.
*/
- idx = duk_require_normalize_index(ctx, idx);
- src = duk__prep_codec_arg(ctx, idx, &srclen);
+ idx = duk_require_normalize_index(thr, idx);
+ src = duk__prep_codec_arg(thr, idx, &srclen);
/* Note: for srclen=0, src may be NULL */
/* Computation must not wrap; this limit works for 32-bit size_t:
@@ -14723,21 +15003,20 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx) {
goto type_error;
}
dstlen = (srclen + 2) / 3 * 4;
- dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, dstlen);
+ dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen);
duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
- ret = duk_buffer_to_string(ctx, -1); /* Safe, result is ASCII. */
- duk_replace(ctx, idx);
+ ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
+ duk_replace(thr, idx);
return ret;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED);
return NULL; /* never here */
}
-DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
@@ -14745,14 +15024,14 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t idx) {
duk_uint8_t *dst_final;
duk_bool_t retval;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: optimize for buffer inputs: no need to coerce to a string
* which causes an unnecessary interning.
*/
- idx = duk_require_normalize_index(ctx, idx);
- src = duk__prep_codec_arg(ctx, idx, &srclen);
+ idx = duk_require_normalize_index(thr, idx);
+ src = duk__prep_codec_arg(thr, idx, &srclen);
/* Computation must not wrap, only srclen + 3 is at risk of
* wrapping because after that the number gets smaller.
@@ -14763,7 +15042,7 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t idx) {
goto type_error;
}
dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
- dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
+ dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen);
/* Note: for dstlen=0, dst may be NULL */
retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
@@ -14772,15 +15051,15 @@ DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t idx) {
}
/* XXX: convert to fixed buffer? */
- (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst));
- duk_replace(ctx, idx);
+ (void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst));
+ duk_replace(thr, idx);
return;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED);
}
-DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
@@ -14791,14 +15070,14 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx) {
duk_uint16_t *p16;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
- inp = duk__prep_codec_arg(ctx, idx, &len);
+ idx = duk_require_normalize_index(thr, idx);
+ inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL || len == 0);
/* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len * 2);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
@@ -14831,13 +15110,12 @@ DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx) {
* caller coerce to string if necessary?
*/
- ret = duk_buffer_to_string(ctx, -1); /* Safe, result is ASCII. */
- duk_replace(ctx, idx);
+ ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
+ duk_replace(thr, idx);
return ret;
}
-DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
@@ -14849,10 +15127,10 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t idx) {
duk_size_t len_safe;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
- inp = duk__prep_codec_arg(ctx, idx, &len);
+ idx = duk_require_normalize_index(thr, idx);
+ inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL || len == 0);
if (len & 0x01) {
@@ -14860,7 +15138,7 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t idx) {
}
/* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len / 2);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
@@ -14913,68 +15191,70 @@ DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t idx) {
}
#endif /* DUK_USE_HEX_FASTPATH */
- duk_replace(ctx, idx);
+ duk_replace(thr, idx);
return;
type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED);
}
#if defined(DUK_USE_JSON_SUPPORT)
-DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
#if defined(DUK_USE_ASSERTIONS)
- top_at_entry = duk_get_top(ctx);
+ top_at_entry = duk_get_top(thr);
#endif
- idx = duk_require_normalize_index(ctx, idx);
- duk_bi_json_stringify_helper(ctx,
+ idx = duk_require_normalize_index(thr, idx);
+ duk_bi_json_stringify_helper(thr,
idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_replacer*/,
DUK_INVALID_INDEX /*idx_space*/,
0 /*flags*/);
- DUK_ASSERT(duk_is_string(ctx, -1));
- duk_replace(ctx, idx);
- ret = duk_get_string(ctx, idx);
+ DUK_ASSERT(duk_is_string(thr, -1));
+ duk_replace(thr, idx);
+ ret = duk_get_string(thr, idx);
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
+ DUK_ASSERT(duk_get_top(thr) == top_at_entry);
return ret;
}
-DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
#if defined(DUK_USE_ASSERTIONS)
- top_at_entry = duk_get_top(ctx);
+ top_at_entry = duk_get_top(thr);
#endif
- idx = duk_require_normalize_index(ctx, idx);
- duk_bi_json_parse_helper(ctx,
+ idx = duk_require_normalize_index(thr, idx);
+ duk_bi_json_parse_helper(thr,
idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_reviver*/,
0 /*flags*/);
- duk_replace(ctx, idx);
+ duk_replace(thr, idx);
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
+ DUK_ASSERT(duk_get_top(thr) == top_at_entry);
}
#else /* DUK_USE_JSON_SUPPORT */
-DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
-DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
#endif /* DUK_USE_JSON_SUPPORT */
/*
@@ -14991,10 +15271,10 @@ struct duk__compile_raw_args {
};
/* Eval is just a wrapper now. */
-DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
+DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk_int_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: strictness is *not* inherited from the current Duktape/C.
* This would be confusing because the current strictness state
@@ -15005,7 +15285,7 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
/* [ ... source? filename? ] (depends on flags) */
- rc = duk_compile_raw(ctx, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */
+ rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */
/* [ ... closure/error ] */
@@ -15014,12 +15294,12 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
goto got_rc;
}
- duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */
+ duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */
if (flags & DUK_COMPILE_SAFE) {
- rc = duk_pcall_method(ctx, 0);
+ rc = duk_pcall_method(thr, 0);
} else {
- duk_call_method(ctx, 0);
+ duk_call_method(thr, 0);
rc = DUK_EXEC_SUCCESS;
}
@@ -15027,20 +15307,19 @@ DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, du
got_rc:
if (flags & DUK_COMPILE_NORESULT) {
- duk_pop(ctx);
+ duk_pop(thr);
}
return rc;
}
/* Helper which can be called both directly and with duk_safe_call(). */
-DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
duk__compile_raw_args *comp_args;
duk_uint_t flags;
duk_hcompfunc *h_templ;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(udata != NULL);
/* Note: strictness is not inherited from the current Duktape/C
@@ -15057,7 +15336,7 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx, void *udata) {
if (flags & DUK_COMPILE_NOFILENAME) {
/* Automatic filename: 'eval' or 'input'. */
- duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
+ duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
}
/* [ ... source? filename ] */
@@ -15065,7 +15344,7 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx, void *udata) {
if (!comp_args->src_buffer) {
duk_hstring *h_sourcecode;
- h_sourcecode = duk_get_hstring(ctx, -2);
+ h_sourcecode = duk_get_hstring(thr, -2);
if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
(h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
@@ -15089,29 +15368,29 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx, void *udata) {
if (flags & DUK_COMPILE_NOSOURCE) {
;
} else {
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
}
/* [ ... func_template ] */
- h_templ = (duk_hcompfunc *) duk_known_hobject(ctx, -1);
+ h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1);
duk_js_push_closure(thr,
h_templ,
thr->builtins[DUK_BIDX_GLOBAL_ENV],
thr->builtins[DUK_BIDX_GLOBAL_ENV],
1 /*add_auto_proto*/);
- duk_remove_m2(ctx); /* -> [ ... closure ] */
+ duk_remove_m2(thr); /* -> [ ... closure ] */
/* [ ... closure ] */
return 1;
}
-DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
+DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk__compile_raw_args comp_args_alloc;
duk__compile_raw_args *comp_args = &comp_args_alloc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
/* String length is computed here to avoid multiple evaluation
@@ -15138,13 +15417,13 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer,
nargs = flags & 0x07;
DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
- rc = duk_safe_call(ctx, duk__do_compile, (void *) comp_args, nargs, nrets);
+ rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets);
/* [ ... closure ] */
return rc;
}
- (void) duk__do_compile(ctx, (void *) comp_args);
+ (void) duk__do_compile(thr, (void *) comp_args);
/* [ ... closure ] */
return DUK_EXEC_SUCCESS;
@@ -15156,48 +15435,49 @@ DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer,
/* #include duk_internal.h -> already included */
#if defined(DUK_USE_JSON_SUPPORT)
-DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
+DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
duk_idx_t idx;
duk_idx_t top;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* We don't duk_require_stack() here now, but rely on the caller having
* enough space.
*/
- top = duk_get_top(ctx);
- duk_push_array(ctx);
+ top = duk_get_top(thr);
+ duk_push_array(thr);
for (idx = 0; idx < top; idx++) {
- duk_dup(ctx, idx);
- duk_put_prop_index(ctx, -2, idx);
+ duk_dup(thr, idx);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) idx);
}
/* XXX: conversion errors should not propagate outwards.
* Perhaps values need to be coerced individually?
*/
- duk_bi_json_stringify_helper(ctx,
- duk_get_top_index(ctx), /*idx_value*/
+ duk_bi_json_stringify_helper(thr,
+ duk_get_top_index(thr), /*idx_value*/
DUK_INVALID_INDEX, /*idx_replacer*/
DUK_INVALID_INDEX, /*idx_space*/
DUK_JSON_FLAG_EXT_CUSTOM |
DUK_JSON_FLAG_ASCII_ONLY |
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
- duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1));
- duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
- duk_pop(ctx);
- DUK_ASSERT(duk_is_string(ctx, -1));
+ duk_push_sprintf(thr, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(thr, -1));
+ duk_replace(thr, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
+ duk_pop(thr);
+ DUK_ASSERT(duk_is_string(thr, -1));
}
#else /* DUK_USE_JSON_SUPPORT */
-DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_UNSUPPORTED(thr);
}
#endif /* DUK_USE_JSON_SUPPORT */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
+DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
duk_debug_read_function read_cb,
duk_debug_write_function write_cb,
duk_debug_peek_function peek_cb,
@@ -15206,7 +15486,6 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
duk_debug_request_function request_cb,
duk_debug_detached_function detached_cb,
void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_heap *heap;
const char *str;
duk_size_t len;
@@ -15217,7 +15496,7 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(read_cb != NULL);
DUK_ASSERT(write_cb != NULL);
/* Other callbacks are optional. */
@@ -15237,10 +15516,9 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
heap->dbg_processing = 0;
heap->dbg_state_dirty = 0;
heap->dbg_force_restart = 0;
- heap->dbg_step_type = DUK_STEP_TYPE_NONE;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
+ heap->dbg_pause_flags = 0;
+ heap->dbg_pause_act = NULL;
+ heap->dbg_pause_startline = 0;
heap->dbg_exec_counter = 0;
heap->dbg_last_counter = 0;
heap->dbg_last_time = 0.0;
@@ -15249,45 +15527,38 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
/* Send version identification and flush right afterwards. Note that
* we must write raw, unframed bytes here.
*/
- duk_push_sprintf(ctx, "%ld %ld %s %s\n",
+ duk_push_sprintf(thr, "%ld %ld %s %s\n",
(long) DUK_DEBUG_PROTOCOL_VERSION,
(long) DUK_VERSION,
(const char *) DUK_GIT_DESCRIBE,
(const char *) DUK_USE_TARGET_INFO);
- str = duk_get_lstring(ctx, -1, &len);
+ str = duk_get_lstring(thr, -1, &len);
DUK_ASSERT(str != NULL);
duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
duk_debug_write_flush(thr);
- duk_pop(ctx);
+ duk_pop(thr);
}
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- duk_hthread *thr;
-
+DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
/* Can be called multiple times with no harm. */
duk_debug_do_detach(thr->heap);
}
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
duk_bool_t processed_messages;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
if (!duk_debug_is_attached(thr->heap)) {
return;
}
- if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
+ if (thr->callstack_curr != NULL || thr->heap->dbg_processing) {
/* Calling duk_debugger_cooperate() while Duktape is being
* called into is not supported. This is not a 100% check
* but prevents any damage in most cases.
@@ -15299,20 +15570,17 @@ DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
DUK_UNREF(processed_messages);
}
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
- duk_hthread *thr;
+DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
duk_idx_t idx;
duk_bool_t ret = 0;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
if (top < nvalues) {
DUK_ERROR_RANGE(thr, "not enough stack values for notify");
return ret; /* unreachable */
@@ -15320,7 +15588,7 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues)
if (duk_debug_is_attached(thr->heap)) {
duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
for (idx = top - nvalues; idx < top; idx++) {
- duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx);
duk_debug_write_tval(thr, tv);
}
duk_debug_write_eom(thr);
@@ -15334,16 +15602,12 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues)
ret = 1;
}
}
- duk_pop_n(ctx, nvalues);
+ duk_pop_n(thr, nvalues);
return ret;
}
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
+DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
@@ -15367,7 +15631,7 @@ DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
#else /* DUK_USE_DEBUGGER_SUPPORT */
-DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
+DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
duk_debug_read_function read_cb,
duk_debug_write_function write_cb,
duk_debug_peek_function peek_cb,
@@ -15376,7 +15640,7 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
duk_debug_request_function request_cb,
duk_debug_detached_function detached_cb,
void *udata) {
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(read_cb);
DUK_UNREF(write_cb);
DUK_UNREF(peek_cb);
@@ -15385,40 +15649,40 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
DUK_UNREF(request_cb);
DUK_UNREF(detached_cb);
DUK_UNREF(udata);
- DUK_ERROR_TYPE((duk_hthread *) ctx, "no debugger support");
+ DUK_ERROR_TYPE(thr, "no debugger support");
}
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ERROR_TYPE((duk_hthread *) ctx, "no debugger support");
+DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ERROR_TYPE(thr, "no debugger support");
}
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
+DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
/* nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
}
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
+DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
if (top < nvalues) {
- DUK_ERROR_RANGE_INVALID_COUNT((duk_hthread *) ctx);
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
return 0; /* unreachable */
}
/* No debugger support, just pop values. */
- duk_pop_n(ctx, nvalues);
+ duk_pop_n(thr, nvalues);
return 0;
}
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
+DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
/* Treat like debugger statement: nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
@@ -15437,14 +15701,13 @@ struct duk_internal_thread_state {
duk_int_t call_recursion_depth;
};
-DUK_EXTERNAL
-duk_context *duk_create_heap(duk_alloc_function alloc_func,
- duk_realloc_function realloc_func,
- duk_free_function free_func,
- void *heap_udata,
- duk_fatal_function fatal_handler) {
+DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func,
+ duk_realloc_function realloc_func,
+ duk_free_function free_func,
+ void *heap_udata,
+ duk_fatal_function fatal_handler) {
duk_heap *heap = NULL;
- duk_context *ctx;
+ duk_hthread *thr;
/* Assume that either all memory funcs are NULL or non-NULL, mixed
* cases will now be unsafe.
@@ -15483,33 +15746,31 @@ duk_context *duk_create_heap(duk_alloc_function alloc_func,
if (!heap) {
return NULL;
}
- ctx = (duk_context *) heap->heap_thread;
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
- return ctx;
+ thr = heap->heap_thread;
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ return thr;
}
-DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) {
duk_heap *heap;
- if (!ctx) {
+ if (!thr) {
return;
}
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
duk_heap_free(heap);
}
-DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) {
duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
duk_heap *heap;
duk_ljstate *lj;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
@@ -15528,8 +15789,8 @@ DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
heap = thr->heap;
lj = &heap->lj;
- duk_push_tval(ctx, &lj->value1);
- duk_push_tval(ctx, &lj->value2);
+ duk_push_tval(thr, &lj->value1);
+ duk_push_tval(thr, &lj->value2);
/* XXX: creating_error == 0 is asserted above, so no need to store. */
DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
@@ -15546,13 +15807,11 @@ DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
heap->call_recursion_depth = 0;
}
-DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
@@ -15569,20 +15828,21 @@ DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
heap->curr_thread = snapshot->curr_thread;
heap->call_recursion_depth = snapshot->call_recursion_depth;
- duk_pop_2(ctx);
+ duk_pop_2(thr);
}
/* XXX: better place for this */
-DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) {
duk_hobject *h_glob;
duk_hobject *h_prev_glob;
duk_hobjenv *h_env;
duk_hobject *h_prev_env;
- DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(thr, -1)));
- h_glob = duk_require_hobject(ctx, -1);
+ h_glob = duk_require_hobject(thr, -1);
DUK_ASSERT(h_glob != NULL);
/*
@@ -15627,7 +15887,7 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
/* [ ... new_glob ] */
- duk_pop(ctx);
+ duk_pop(thr);
/* [ ... ] */
}
@@ -15640,7 +15900,7 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
/* For footprint efficient multiple value setting: arrays are much better than
* varargs, format string with parsing is often better than string pointer arrays.
*/
-DUK_LOCAL void duk__inspect_multiple_uint(duk_context *ctx, const char *fmt, duk_int_t *vals) {
+DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) {
duk_int_t val;
const char *p;
const char *p_curr;
@@ -15657,9 +15917,9 @@ DUK_LOCAL void duk__inspect_multiple_uint(duk_context *ctx, const char *fmt, duk
val = *vals++;
if (val >= 0) {
/* Negative values are markers to skip key. */
- duk_push_string(ctx, p_curr);
- duk_push_uint(ctx, val);
- duk_put_prop(ctx, -3);
+ duk_push_string(thr, p_curr);
+ duk_push_int(thr, val);
+ duk_put_prop(thr, -3);
}
}
}
@@ -15687,8 +15947,7 @@ DUK_LOCAL void duk__inspect_multiple_uint(duk_context *ctx, const char *fmt, duk
#define DUK__IDX_TSTATE 12
#define DUK__IDX_VARIANT 13
-DUK_EXTERNAL void duk_inspect_value(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_heaphdr *h;
/* The temporary values should be in an array rather than individual
@@ -15697,31 +15956,31 @@ DUK_EXTERNAL void duk_inspect_value(duk_context *ctx, duk_idx_t idx) {
*/
duk_int_t vals[14];
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
/* Assume two's complement and set everything to -1. */
DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals));
DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL);
vals[DUK__IDX_TYPE] = duk_get_type_tval(tv);
- vals[DUK__IDX_ITAG] = (duk_uint_t) DUK_TVAL_GET_TAG(tv);
+ vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv);
- duk_push_bare_object(ctx); /* Invalidates 'tv'. */
+ duk_push_bare_object(thr); /* Invalidates 'tv'. */
tv = NULL;
if (h == NULL) {
goto finish;
}
- duk_push_pointer(ctx, (void *) h);
- duk_put_prop_string(ctx, -2, "hptr");
+ duk_push_pointer(thr, (void *) h);
+ duk_put_prop_string(thr, -2, "hptr");
#if 0
/* Covers a lot of information, e.g. buffer and string variants. */
- duk_push_uint(ctx, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
- duk_put_prop_string(ctx, -2, "hflags");
+ duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
+ duk_put_prop_string(thr, -2, "hflags");
#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
@@ -15800,62 +16059,61 @@ DUK_EXTERNAL void duk_inspect_value(duk_context *ctx, duk_idx_t idx) {
vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */
vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic));
}
- vals[DUK__IDX_DBYTES] = (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf));
+ vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf));
} else {
DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */
- vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
+ vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
}
break;
}
}
finish:
- duk__inspect_multiple_uint(ctx,
+ duk__inspect_multiple_uint(thr,
"type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00"
"pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00"
"bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00",
(duk_int_t *) &vals);
}
-DUK_EXTERNAL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) {
duk_activation *act;
duk_uint_fast32_t pc;
duk_uint_fast32_t line;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- /* -1 = top callstack entry, callstack[callstack_top - 1]
- * -callstack_top = bottom callstack entry, callstack[0]
+ /* -1 = top callstack entry
+ * -2 = caller of level -1
+ * etc
*/
- if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
- duk_push_undefined(ctx);
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act == NULL) {
+ duk_push_undefined(thr);
return;
}
- duk_push_bare_object(ctx);
- DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
+ duk_push_bare_object(thr);
- act = thr->callstack + thr->callstack_top + level;
/* Relevant PC is just before current one because PC is
* post-incremented. This should match what error augment
* code does.
*/
pc = duk_hthread_get_act_prev_pc(thr, act);
- duk_push_tval(ctx, &act->tv_func);
+ duk_push_tval(thr, &act->tv_func);
- duk_push_uint(ctx, (duk_uint_t) pc);
- duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_PC);
+ duk_push_uint(thr, (duk_uint_t) pc);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC);
#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -1, pc);
+ line = duk_hobject_pc2line_query(thr, -1, pc);
#else
line = 0;
#endif
- duk_push_uint(ctx, (duk_uint_t) line);
- duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_LINE_NUMBER);
+ duk_push_uint(thr, (duk_uint_t) line);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER);
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_LC_FUNCTION);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION);
/* Providing access to e.g. act->lex_env would be dangerous: these
* internal structures must never be accessible to the application.
* Duktape relies on them having consistent data, and this consistency
@@ -15884,50 +16142,38 @@ DUK_EXTERNAL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level)
/* #include duk_internal.h -> already included */
-DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC_RAW(thr->heap, size);
}
-DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_FREE_RAW(thr->heap, ptr);
}
-DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_REALLOC_RAW(thr->heap, ptr, size);
}
-DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC(thr->heap, size);
}
-DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_FREE(thr->heap, ptr);
+ DUK_FREE_CHECKED(thr, ptr);
}
-DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) {
+ DUK_ASSERT_API_ENTRY(thr);
/*
* Note: since this is an exposed API call, there should be
@@ -15942,11 +16188,10 @@ DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
return DUK_REALLOC(thr->heap, ptr, size);
}
-DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) {
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(out_funcs != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
@@ -15958,12 +16203,11 @@ DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_function
out_funcs->udata = heap->heap_udata;
}
-DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) {
duk_heap *heap;
duk_small_uint_t ms_flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
@@ -15986,94 +16230,98 @@ DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
* defineProperty, getOwnPropertyDescriptor).
*/
-DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property get right now.
*/
- tv_obj = duk_require_tval(ctx, obj_idx);
- tv_key = duk_require_tval(ctx, -1);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
rc = duk_hobject_getprop(thr, tv_obj, tv_key);
DUK_ASSERT(rc == 0 || rc == 1);
/* a value is left on stack regardless of rc */
- duk_remove_m2(ctx); /* remove key */
+ duk_remove_m2(thr); /* remove key */
+ DUK_ASSERT(duk_is_undefined(thr, -1) || rc == 1);
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_string(ctx, key);
- return duk_get_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_lstring(ctx, key, key_len);
- return duk_get_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_uarridx(ctx, arr_idx);
- return duk_get_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_get_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_get_prop(thr, obj_idx);
+}
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
- DUK_UNREF(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_get_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_get_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
- return duk_get_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_get_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
(duk_small_uint_t) (packed_args & 0xffffUL));
}
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) {
+DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) {
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
- rc = duk_get_prop_stridx(ctx, obj_idx, stridx);
+ rc = duk_get_prop_stridx(thr, obj_idx, stridx);
if (out_has_prop) {
*out_has_prop = rc;
}
- rc = duk_to_boolean(ctx, -1);
+ rc = duk_to_boolean(thr, -1);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx);
+ duk_pop(thr);
return rc;
}
-DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_tval *tv_val;
- duk_small_int_t throw_flag;
+ duk_bool_t throw_flag;
duk_bool_t rc;
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
@@ -16087,202 +16335,216 @@ DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, d
DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
(idx_key == -1 && (idx_key ^ 1) == -2));
/* XXX: Direct access; faster validation. */
- tv_obj = duk_require_tval(ctx, obj_idx);
- tv_key = duk_require_tval(ctx, idx_key);
- tv_val = duk_require_tval(ctx, idx_key ^ 1);
- throw_flag = duk_is_strict_call(ctx);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, idx_key);
+ tv_val = duk_require_tval(thr, idx_key ^ 1);
+ throw_flag = duk_is_strict_call(thr);
rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop_2(ctx); /* remove key and value */
+ duk_pop_2(thr); /* remove key and value */
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__put_prop_shared(ctx, obj_idx, -2);
+DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__put_prop_shared(thr, obj_idx, -2);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
/* Careful here and with other duk_put_prop_xxx() helpers: the
* target object and the property value may be in the same value
* stack slot (unusual, but still conceptually clear).
*/
- obj_idx = duk_normalize_index(ctx, obj_idx);
- (void) duk_push_string(ctx, key);
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_normalize_index(thr, obj_idx);
+ (void) duk_push_string(thr, key);
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_idx = duk_normalize_index(ctx, obj_idx);
- (void) duk_push_lstring(ctx, key, key_len);
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_normalize_index(thr, obj_idx);
+ (void) duk_push_lstring(thr, key, key_len);
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_uarridx(ctx, arr_idx);
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk__put_prop_shared(thr, obj_idx, -1);
+}
+
+DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
- DUK_UNREF(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk__put_prop_shared(ctx, obj_idx, -1);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk__put_prop_shared(thr, obj_idx, -1);
}
-DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
- return duk_put_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_put_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
(duk_small_uint_t) (packed_args & 0xffffUL));
}
-DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
- duk_small_int_t throw_flag;
+ duk_bool_t throw_flag;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property delete right now.
*/
- tv_obj = duk_require_tval(ctx, obj_idx);
- tv_key = duk_require_tval(ctx, -1);
- throw_flag = duk_is_strict_call(ctx);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
+ throw_flag = duk_is_strict_call(thr);
rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx); /* remove key */
+ duk_pop(thr); /* remove key */
return rc;
}
-DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_string(ctx, key);
- return duk_del_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_lstring(ctx, key, key_len);
- return duk_del_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_uarridx(ctx, arr_idx);
- return duk_del_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_del_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_del_prop(thr, obj_idx);
+}
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
- DUK_UNREF(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_del_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_del_prop(thr, obj_idx);
}
#if 0
-DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
- return duk_del_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_del_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
(duk_small_uint_t) (packed_args & 0xffffUL));
}
#endif
-DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t rc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: copying tv_obj and tv_key to locals to shield against a valstack
* resize is not necessary for a property existence check right now.
*/
- tv_obj = duk_require_tval(ctx, obj_idx);
- tv_key = duk_require_tval(ctx, -1);
+ tv_obj = duk_require_tval(thr, obj_idx);
+ tv_key = duk_require_tval(thr, -1);
rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx); /* remove key */
+ duk_pop(thr); /* remove key */
return rc; /* 1 if property found, 0 otherwise */
}
-DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_string(ctx, key);
- return duk_has_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_string(thr, key);
+ return duk_has_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(key != NULL);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_lstring(ctx, key, key_len);
- return duk_has_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_lstring(thr, key, key_len);
+ return duk_has_prop(thr, obj_idx);
}
-DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_uarridx(ctx, arr_idx);
- return duk_has_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_uarridx(thr, arr_idx);
+ return duk_has_prop(thr, obj_idx);
}
-DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ return duk_has_prop(thr, obj_idx);
+}
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
- DUK_UNREF(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_has_prop(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ return duk_has_prop(thr, obj_idx);
}
#if 0
-DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
- return duk_has_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
+DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ return duk_has_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
(duk_small_uint_t) (packed_args & 0xffffUL));
}
#endif
@@ -16292,103 +16554,103 @@ DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_context *ctx, duk_uint
* not invoked by this method. The caller must be careful to invoke any such
* behaviors if necessary.
*/
-DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_idx);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
- key = duk_to_property_key_hstring(ctx, -2);
+ key = duk_to_property_key_hstring(thr, -2);
DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
+ DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
- duk_pop(ctx); /* pop key */
+ duk_pop(thr); /* pop key */
}
-DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_idx);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags);
/* value popped by call */
}
-DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
- obj = duk_require_hobject(ctx, obj_idx);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
key = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
+ DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
/* value popped by call */
}
-DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
- duk_xdef_prop_stridx(ctx, (duk_idx_t) (duk_int8_t) (packed_args >> 24),
+DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
+ duk_xdef_prop_stridx(thr, (duk_idx_t) (duk_int8_t) (packed_args >> 24),
(duk_small_uint_t) (packed_args >> 8) & 0xffffUL,
(duk_small_uint_t) (packed_args & 0xffL));
}
-DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+#if 0 /*unused*/
+DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
duk_hobject *obj;
duk_hstring *key;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
DUK_ASSERT_BIDX_VALID(builtin_idx);
- obj = duk_require_hobject(ctx, obj_idx);
+ obj = duk_require_hobject(thr, obj_idx);
DUK_ASSERT(obj != NULL);
key = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(key != NULL);
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
+ duk_push_hobject(thr, thr->builtins[builtin_idx]);
duk_hobject_define_property_internal(thr, obj, key, desc_flags);
/* value popped by call */
}
+#endif
/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
* setter/getter into an object property. This is needed by the 'arguments'
* object creation code, function instance creation code, and Function.prototype.bind().
*/
-DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
- duk_push_hstring_stridx(ctx, stridx);
- duk_push_hobject_bidx(ctx, DUK_BIDX_TYPE_ERROR_THROWER);
- duk_dup_top(ctx);
- duk_def_prop(ctx, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */
+DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ duk_push_hstring_stridx(thr, stridx);
+ duk_push_hobject_bidx(thr, DUK_BIDX_TYPE_ERROR_THROWER);
+ duk_dup_top(thr);
+ duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */
}
/* Object.getOwnPropertyDescriptor() equivalent C binding. */
-DUK_EXTERNAL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) {
+DUK_EXTERNAL void duk_get_prop_desc(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(flags); /* no flags defined yet */
- duk_hobject_object_get_own_property_descriptor(ctx, obj_idx); /* [ ... key ] -> [ ... desc ] */
+ duk_hobject_object_get_own_property_descriptor(thr, obj_idx); /* [ ... key ] -> [ ... desc ] */
}
/* Object.defineProperty() equivalent C binding. */
-DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
duk_idx_t idx_base;
duk_hobject *obj;
duk_hstring *key;
@@ -16398,9 +16660,9 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t f
duk_uint_t is_data_desc;
duk_uint_t is_acc_desc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, obj_idx);
+ obj = duk_require_hobject(thr, obj_idx);
is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
@@ -16412,12 +16674,12 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t f
goto fail_invalid_desc;
}
- idx_base = duk_get_top_index(ctx);
+ idx_base = duk_get_top_index(thr);
if (flags & DUK_DEFPROP_HAVE_SETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC);
- set = duk_get_hobject_promote_lfunc(ctx, idx_base);
+ set = duk_get_hobject_promote_lfunc(thr, idx_base);
if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
goto fail_not_callable;
}
@@ -16426,10 +16688,10 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t f
set = NULL;
}
if (flags & DUK_DEFPROP_HAVE_GETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC);
- get = duk_get_hobject_promote_lfunc(ctx, idx_base);
+ get = duk_get_hobject_promote_lfunc(thr, idx_base);
if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
goto fail_not_callable;
}
@@ -16443,12 +16705,12 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t f
} else {
idx_value = (duk_idx_t) -1;
}
- key = duk_to_property_key_hstring(ctx, idx_base);
+ key = duk_to_property_key_hstring(thr, idx_base);
DUK_ASSERT(key != NULL);
- duk_require_valid_index(ctx, idx_base);
+ duk_require_valid_index(thr, idx_base);
- duk_hobject_define_property_helper(ctx,
+ duk_hobject_define_property_helper(thr,
flags /*defprop_flags*/,
obj,
key,
@@ -16459,7 +16721,7 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t f
/* Clean up stack */
- duk_set_top(ctx, idx_base);
+ duk_set_top(thr, idx_base);
/* [ ... obj ... ] */
@@ -16481,73 +16743,140 @@ DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t f
* and are not exposed through the API.
*/
-DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_compact(duk_hthread *thr, duk_idx_t obj_idx) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, obj_idx);
+ obj = duk_get_hobject(thr, obj_idx);
if (obj) {
/* Note: this may fail, caller should protect the call if necessary */
duk_hobject_compact_props(thr, obj);
}
}
-DUK_INTERNAL void duk_compact_m1(duk_context *ctx) {
- duk_compact(ctx, -1);
+DUK_INTERNAL void duk_compact_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_compact(thr, -1);
}
/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
-DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_enum(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t enum_flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_dup(thr, obj_idx);
+ duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ duk_hobject_enumerator_create(thr, enum_flags); /* [target] -> [enum] */
+}
+
+DUK_EXTERNAL duk_bool_t duk_next(duk_hthread *thr, duk_idx_t enum_index, duk_bool_t get_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_require_hobject(thr, enum_index);
+ duk_dup(thr, enum_index);
+ return duk_hobject_enumerator_next(thr, get_value);
+}
+
+DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze) {
+ duk_tval *tv;
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, obj_idx);
+ DUK_ASSERT(tv != NULL);
+
+ /* Seal/freeze are quite rare in practice so it'd be nice to get the
+ * correct behavior simply via automatic promotion (at the cost of some
+ * memory churn). However, the promoted objects don't behave the same,
+ * e.g. promoted lightfuncs are extensible.
+ */
+
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_BUFFER:
+ /* Plain buffer: already sealed, but not frozen (and can't be frozen
+ * because index properties can't be made non-writable.
+ */
+ if (is_freeze) {
+ goto fail_cannot_freeze;
+ }
+ break;
+ case DUK_TAG_LIGHTFUNC:
+ /* Lightfunc: already sealed and frozen, success. */
+ break;
+ case DUK_TAG_OBJECT:
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) {
+ /* Buffer objects cannot be frozen because there's no internal
+ * support for making virtual array indices non-writable.
+ */
+ DUK_DD(DUK_DDPRINT("cannot freeze a buffer object"));
+ goto fail_cannot_freeze;
+ }
+ duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
+
+ /* Sealed and frozen objects cannot gain any more properties,
+ * so this is a good time to compact them.
+ */
+ duk_hobject_compact_props(thr, h);
+ break;
+ default:
+ /* ES2015 Sections 19.1.2.5, 19.1.2.17 */
+ break;
+ }
+ return;
+
+ fail_cannot_freeze:
+ DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */
+}
+
+DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_dup(ctx, obj_idx);
- duk_require_hobject_promote_mask(ctx, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
- duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */
+ duk_seal_freeze_raw(thr, obj_idx, 0 /*is_freeze*/);
}
-DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_freeze(duk_hthread *thr, duk_idx_t obj_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_require_hobject(ctx, enum_index);
- duk_dup(ctx, enum_index);
- return duk_hobject_enumerator_next(ctx, get_value);
+ duk_seal_freeze_raw(thr, obj_idx, 1 /*is_freeze*/);
}
/*
* Helpers for writing multiple properties
*/
-DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, const duk_function_list_entry *funcs) {
+DUK_EXTERNAL void duk_put_function_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_function_list_entry *funcs) {
const duk_function_list_entry *ent = funcs;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
if (ent != NULL) {
while (ent->key != NULL) {
- duk_push_c_function(ctx, ent->value, ent->nargs);
- duk_put_prop_string(ctx, obj_idx, ent->key);
+ duk_push_c_function(thr, ent->value, ent->nargs);
+ duk_put_prop_string(thr, obj_idx, ent->key);
ent++;
}
}
}
-DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers) {
+DUK_EXTERNAL void duk_put_number_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_number_list_entry *numbers) {
const duk_number_list_entry *ent = numbers;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj_idx = duk_require_normalize_index(ctx, obj_idx);
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
if (ent != NULL) {
while (ent->key != NULL) {
- tv = ((duk_hthread *) ctx)->valstack_top++;
+ tv = thr->valstack_top++;
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */
DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */
- duk_put_prop_string(ctx, obj_idx, ent->key);
+ duk_put_prop_string(thr, obj_idx, ent->key);
ent++;
}
}
@@ -16557,65 +16886,61 @@ DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const
* Shortcut for accessing global object properties
*/
-DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- ret = duk_get_prop_string(ctx, -1, key);
- duk_remove_m2(ctx);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_string(thr, -1, key);
+ duk_remove_m2(thr);
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- ret = duk_get_prop_lstring(ctx, -1, key, key_len);
- duk_remove_m2(ctx);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_lstring(thr, -1, key, key_len);
+ duk_remove_m2(thr);
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- duk_insert(ctx, -2);
- ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */
- duk_pop(ctx);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_string(thr, -2, key); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
/* XXX: direct implementation */
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- duk_insert(ctx, -2);
- ret = duk_put_prop_lstring(ctx, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
- duk_pop(ctx);
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_lstring(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
return ret;
}
@@ -16623,38 +16948,35 @@ DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key
* Object prototype
*/
-DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_get_prototype(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
duk_hobject *proto;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, idx);
+ obj = duk_require_hobject(thr, idx);
DUK_ASSERT(obj != NULL);
/* XXX: shared helper for duk_push_hobject_or_undefined()? */
proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
if (proto) {
- duk_push_hobject(ctx, proto);
+ duk_push_hobject(thr, proto);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
duk_hobject *proto;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_require_hobject(ctx, idx);
+ obj = duk_require_hobject(thr, idx);
DUK_ASSERT(obj != NULL);
- duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, -1, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_OBJECT);
- proto = duk_get_hobject(ctx, -1);
+ proto = duk_get_hobject(thr, -1);
/* proto can also be NULL here (allowed explicitly) */
#if defined(DUK_USE_ROM_OBJECTS)
@@ -16666,7 +16988,7 @@ DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t idx) {
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
- duk_pop(ctx);
+ duk_pop(thr);
}
/*
@@ -16679,21 +17001,21 @@ DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t idx) {
* XXX: same issue as with Duktape.fin: there's no way to delete the property
* now (just set it to undefined).
*/
-DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_get_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER);
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
}
-DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *h;
duk_bool_t callable;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_require_hobject(ctx, idx); /* Get before 'put' so that 'idx' is correct. */
- callable = duk_is_callable(ctx, -1);
- duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER);
+ h = duk_require_hobject(thr, idx); /* Get before 'put' so that 'idx' is correct. */
+ callable = duk_is_callable(thr, -1);
+ duk_put_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
/* In addition to setting the finalizer property, keep a "have
* finalizer" flag in duk_hobject in sync so that refzero can do
@@ -16713,16 +17035,16 @@ DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
}
}
#else /* DUK_USE_FINALIZER_SUPPORT */
-DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
-DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
@@ -16743,7 +17065,7 @@ DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
* Forward declarations
*/
-DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags);
+DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx);
/*
* Global state for working around missing variadic macros
@@ -16758,6 +17080,10 @@ DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
* Misc helpers
*/
+DUK_LOCAL const char * const duk__symbol_type_strings[4] = {
+ "hidden", "global", "local", "wellknown"
+};
+
#if !defined(DUK_USE_PACKED_TVAL)
DUK_LOCAL const duk_uint_t duk__type_from_tag[] = {
DUK_TYPE_NUMBER,
@@ -16787,12 +17113,15 @@ DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = {
};
#endif /* !DUK_USE_PACKED_TVAL */
+/* Assert that there's room for one value. */
+#define DUK__ASSERT_SPACE() do { \
+ DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
+ } while (0)
+
/* 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 { \
- DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
- } while (0)
+#define DUK__CHECK_SPACE() DUK__ASSERT_SPACE()
#else
#define DUK__CHECK_SPACE() do { \
if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
@@ -16801,17 +17130,48 @@ DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = {
} while (0)
#endif
-DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag);
+DUK_LOCAL duk_small_uint_t duk__get_symbol_type(duk_hstring *h) {
+ const duk_uint8_t *data;
+ duk_size_t len;
-DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) {
- duk_hthread *thr;
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HSTRING_HAS_SYMBOL(h));
+ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h) >= 1); /* always true, symbol prefix */
+
+ data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
+ len = DUK_HSTRING_GET_BYTELEN(h);
+ DUK_ASSERT(len >= 1);
+
+ /* XXX: differentiate between 0x82 and 0xff (hidden vs. internal?)? */
+
+ if (data[0] == 0xffU) {
+ return DUK_SYMBOL_TYPE_HIDDEN;
+ } else if (data[0] == 0x82U) {
+ return DUK_SYMBOL_TYPE_HIDDEN;
+ } else if (data[0] == 0x80U) {
+ return DUK_SYMBOL_TYPE_GLOBAL;
+ } else if (data[len - 1] != 0xffU) {
+ return DUK_SYMBOL_TYPE_LOCAL;
+ } else {
+ return DUK_SYMBOL_TYPE_WELLKNOWN;
+ }
+}
+
+DUK_LOCAL const char *duk__get_symbol_type_string(duk_hstring *h) {
+ duk_small_uint_t idx;
+ idx = duk__get_symbol_type(h);
+ DUK_ASSERT(idx < sizeof(duk__symbol_type_strings));
+ return duk__symbol_type_strings[idx];
+}
+
+DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag);
+
+DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) {
duk_tval *tv;
duk_small_int_t c;
duk_double_t d;
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
/*
@@ -16867,17 +17227,14 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_int
return def_value;
}
-DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) {
- duk_hthread *thr;
+DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) {
duk_tval *tv;
duk_small_int_t c;
duk_double_t d;
/* Same as above but for unsigned int range. */
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
#if defined(DUK_USE_FASTINT)
@@ -16930,12 +17287,11 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_u
* There's some repetition because of this; keep the functions in sync.
*/
-DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
/* Care must be taken to avoid pointer wrapping in the index
@@ -16966,12 +17322,11 @@ DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx) {
return DUK_INVALID_INDEX;
}
-DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -16995,12 +17350,11 @@ DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t i
return 0; /* unreachable */
}
-DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -17031,21 +17385,23 @@ DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t idx) {
*/
DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER();
-DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- tv = duk_get_tval(ctx, idx);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval(thr, idx);
if (tv != NULL) {
return tv;
}
return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused);
}
-DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
duk_uidx_t uidx;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -17071,21 +17427,19 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t idx) {
}
/* Non-critical. */
-DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
- return (duk_normalize_index(ctx, idx) >= 0);
+ return (duk_normalize_index(thr, idx) >= 0);
}
/* Non-critical. */
-DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
- if (DUK_UNLIKELY(duk_normalize_index(ctx, idx) < 0)) {
+ if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) {
DUK_ERROR_RANGE_INDEX(thr, idx);
return; /* unreachable */
}
@@ -17095,10 +17449,8 @@ DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx) {
* Value stack top handling
*/
-DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
}
@@ -17106,11 +17458,10 @@ DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
/* Internal helper to get current top but to require a minimum top value
* (TypeError if not met).
*/
-DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
if (DUK_UNLIKELY(ret < min_top)) {
@@ -17123,14 +17474,13 @@ DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_t
* This is performance critical especially for call handling, so whenever
* changing, profile and look at generated code.
*/
-DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) {
duk_uidx_t vs_size;
duk_uidx_t vs_limit;
duk_uidx_t uidx;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_INVALID_INDEX < 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
@@ -17219,11 +17569,98 @@ DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t idx) {
}
}
-DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+/* Internal variant with a non-negative index and no runtime size checks. */
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_set_top(thr, idx);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ duk_uidx_t uidx;
+ duk_uidx_t vs_size;
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
+ DUK_ASSERT(idx >= 0);
+ DUK_ASSERT(idx <= (duk_idx_t) (thr->valstack_end - thr->valstack_bottom));
+
+ /* XXX: byte arithmetic */
+ uidx = (duk_uidx_t) idx;
+ vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
+
+ if (uidx >= vs_size) {
+ /* Stack size increases or stays the same. */
+#if defined(DUK_USE_ASSERTIONS)
+ duk_uidx_t count;
+
+ count = uidx - vs_size;
+ while (count != 0) {
+ count--;
+ tv = thr->valstack_top + count;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
+ }
+#endif
+ thr->valstack_top = thr->valstack_bottom + uidx;
+ } else {
+ /* Stack size decreases. */
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ duk_uidx_t count;
+ duk_tval *tv_end;
+
+ count = vs_size - uidx;
+ DUK_ASSERT(count > 0);
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end); /* Because count > 0. */
+ do {
+ tv--;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+ DUK_REFZERO_CHECK_FAST(thr);
+#else /* DUK_USE_REFERENCE_COUNTING */
+ duk_uidx_t count;
+ duk_tval *tv_end;
+
+ count = vs_size - uidx;
+ tv = thr->valstack_top;
+ tv_end = tv - count;
+ DUK_ASSERT(tv > tv_end);
+ do {
+ tv--;
+ DUK_TVAL_SET_UNDEFINED(tv);
+ } while (tv != tv_end);
+ thr->valstack_top = tv_end;
+#endif /* DUK_USE_REFERENCE_COUNTING */
+ }
+}
+#endif /* DUK_USE_PREFER_SIZE */
+
+/* Internal helper: set top to 'top', and set [idx_wipe_start,top[ to
+ * 'undefined' (doing nothing if idx_wipe_start == top). Indices are
+ * positive and within value stack reserve. This is used by call handling.
+ */
+DUK_INTERNAL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(top >= 0);
+ DUK_ASSERT(idx_wipe_start >= 0);
+ DUK_ASSERT(idx_wipe_start <= top);
+ DUK_ASSERT(thr->valstack_bottom + top <= thr->valstack_end);
+ DUK_ASSERT(thr->valstack_bottom + idx_wipe_start <= thr->valstack_end);
+
+ duk_set_top_unsafe(thr, idx_wipe_start);
+ duk_set_top_unsafe(thr, top);
+}
+
+DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_hthread *thr) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
if (DUK_UNLIKELY(ret < 0)) {
@@ -17239,21 +17676,19 @@ DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
/* Internal variant: call assumes there is at least one element on the value
* stack frame; this is only asserted for.
*/
-DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
return ret;
}
-DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) {
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
if (DUK_UNLIKELY(ret < 0)) {
@@ -17268,61 +17703,71 @@ DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
*
* This resizing happens above the current "top": the value stack can be
* grown or shrunk, but the "top" is not affected. The value stack cannot
- * be resized to a size below the current "top".
+ * be resized to a size below the current reserve.
*
* The low level reallocation primitive must carefully recompute all value
* stack pointers, and must also work if ALL pointers are NULL. The resize
* is quite tricky because the valstack realloc may cause a mark-and-sweep,
* which may run finalizers. Running finalizers may resize the valstack
* recursively (the same value stack we're working on). So, after realloc
- * returns, we know that the valstack "top" should still be the same (there
- * should not be live values above the "top"), but its underlying size and
- * pointer may have changed.
+ * returns, we know that the valstack bottom, top, and reserve should still
+ * be the same (there should not be live values above the "top"), but its
+ * underlying size, alloc_end, and base pointer may have changed.
+ *
+ * 'new_size' is known to be <= DUK_USE_VALSTACK_LIMIT, which ensures that
+ * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
*/
-/* XXX: perhaps refactor this to allow caller to specify some parameters, or
- * at least a 'compact' flag which skips any spare or round-up .. useful for
- * emergency gc.
+/* Low level valstack resize primitive, used for both grow and shrink. All
+ * adjustments for slack etc have already been done. Doesn't throw but does
+ * have allocation side effects.
*/
-
-DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_ptrdiff_t old_bottom_offset;
- duk_ptrdiff_t old_top_offset;
- duk_ptrdiff_t old_end_offset_post;
-#if defined(DUK_USE_DEBUG)
- duk_ptrdiff_t old_end_offset_pre;
- duk_tval *old_valstack_pre;
- duk_tval *old_valstack_post;
-#endif
+DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__resize_valstack(duk_hthread *thr, duk_size_t new_size) {
+ duk_tval *pre_valstack;
+ duk_tval *pre_bottom;
+ duk_tval *pre_top;
+ duk_tval *pre_end;
+ duk_tval *pre_alloc_end;
+ duk_ptrdiff_t ptr_diff;
duk_tval *new_valstack;
duk_size_t new_alloc_size;
+ duk_tval *tv_prev_alloc_end;
duk_tval *p;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_HTHREAD_VALID(thr);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
- DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */
+ DUK_ASSERT(new_size <= DUK_USE_VALSTACK_LIMIT); /* valstack limit caller has check, prevents wrapping */
DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
- /* get pointer offsets for tweaking below */
- old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
- old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
-#if defined(DUK_USE_DEBUG)
- old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */
- old_valstack_pre = thr->valstack;
-#endif
+ /* Pre-realloc pointer copies for asserts and debug logs. */
+ pre_valstack = thr->valstack;
+ pre_bottom = thr->valstack_bottom;
+ pre_top = thr->valstack_top;
+ pre_end = thr->valstack_end;
+ pre_alloc_end = thr->valstack_alloc_end;
- /* Allocate a new valstack.
- *
- * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
- * invalidate the original thr->valstack base pointer inside the realloc
- * process. See doc/memory-management.rst.
+ DUK_UNREF(pre_valstack);
+ DUK_UNREF(pre_bottom);
+ DUK_UNREF(pre_top);
+ DUK_UNREF(pre_end);
+ DUK_UNREF(pre_alloc_end);
+
+ /* If finalizer torture enabled, force base pointer change every time
+ * when it would be allowed.
*/
+#if defined(DUK_USE_FINALIZER_TORTURE)
+ if (thr->heap->pf_prevent_count == 0) {
+ duk_hthread_valstack_torture_realloc(thr);
+ }
+#endif
+ /* Allocate a new valstack using DUK_REALLOC_DIRECT() to deal with
+ * a side effect changing the base pointer.
+ */
new_alloc_size = sizeof(duk_tval) * new_size;
new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
if (DUK_UNLIKELY(new_valstack == NULL)) {
@@ -17335,69 +17780,78 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
return 0;
}
- /* Note: the realloc may have triggered a mark-and-sweep which may
- * have resized our valstack internally. However, the mark-and-sweep
- * MUST NOT leave the stack bottom/top in a different state. Particular
- * assumptions and facts:
- *
- * - The thr->valstack pointer may be different after realloc,
- * and the offset between thr->valstack_end <-> thr->valstack
- * may have changed.
- * - The offset between thr->valstack_bottom <-> thr->valstack
- * and thr->valstack_top <-> thr->valstack MUST NOT have changed,
- * because mark-and-sweep must adhere to a strict stack policy.
- * In other words, logical bottom and top MUST NOT have changed.
- * - All values above the top are unreachable but are initialized
- * to UNDEFINED, up to the post-realloc valstack_end.
- * - 'old_end_offset' must be computed after realloc to be correct.
- */
-
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
-
- /* success, fixup pointers */
- old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */
+ /* Debug log any changes in pointer(s) by side effects. These don't
+ * necessarily imply any incorrect behavior, but should be rare in
+ * practice.
+ */
#if defined(DUK_USE_DEBUG)
- old_valstack_post = thr->valstack;
+ if (thr->valstack != pre_valstack) {
+ DUK_D(DUK_DPRINT("valstack base pointer changed during valstack resize: %p -> %p",
+ (void *) pre_valstack, (void *) thr->valstack));
+ }
+ if (thr->valstack_bottom != pre_bottom) {
+ DUK_D(DUK_DPRINT("valstack bottom pointer changed during valstack resize: %p -> %p",
+ (void *) pre_bottom, (void *) thr->valstack_bottom));
+ }
+ if (thr->valstack_top != pre_top) {
+ DUK_D(DUK_DPRINT("valstack top pointer changed during valstack resize: %p -> %p",
+ (void *) pre_top, (void *) thr->valstack_top));
+ }
+ if (thr->valstack_end != pre_end) {
+ DUK_D(DUK_DPRINT("valstack end pointer changed during valstack resize: %p -> %p",
+ (void *) pre_end, (void *) thr->valstack_end));
+ }
+ if (thr->valstack_alloc_end != pre_alloc_end) {
+ DUK_D(DUK_DPRINT("valstack alloc_end pointer changed during valstack resize: %p -> %p",
+ (void *) pre_alloc_end, (void *) thr->valstack_alloc_end));
+ }
#endif
+
+ /* Assertions: offsets for bottom, top, and end (reserve) must not
+ * have changed even with side effects because they are always
+ * restored in unwind. For alloc_end there's no guarantee: it may
+ * have grown or shrunk (but remain above 'end').
+ */
+ DUK_ASSERT(thr->valstack_bottom - thr->valstack == pre_bottom - pre_valstack);
+ DUK_ASSERT(thr->valstack_top - thr->valstack == pre_top - pre_valstack);
+ DUK_ASSERT(thr->valstack_end - thr->valstack == pre_end - pre_valstack);
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
+
+ /* Write new pointers. Most pointers can be handled as a pointer
+ * difference.
+ */
+ ptr_diff = (duk_ptrdiff_t) ((duk_uint8_t *) new_valstack - (duk_uint8_t *) thr->valstack);
+ tv_prev_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_alloc_end + ptr_diff);
thr->valstack = new_valstack;
- thr->valstack_end = new_valstack + new_size;
-#if !defined(DUK_USE_PREFER_SIZE)
- thr->valstack_size = new_size;
-#endif
- thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
- thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset);
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + ptr_diff);
+ thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + ptr_diff);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_end + ptr_diff);
+ thr->valstack_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + new_alloc_size);
+ /* Assertions: pointer sanity after pointer updates. */
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-
- /* useful for debugging */
-#if defined(DUK_USE_DEBUG)
- if (old_end_offset_pre != old_end_offset_post) {
- DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
- "end offset changed: %lu -> %lu",
- (unsigned long) old_end_offset_pre,
- (unsigned long) old_end_offset_post));
- }
- if (old_valstack_pre != old_valstack_post) {
- DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
- (void *) old_valstack_pre,
- (void *) old_valstack_post));
- }
-#endif
-
- DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, "
- "new pointers: start=%p end=%p bottom=%p top=%p",
- (unsigned long) new_size, (unsigned long) new_alloc_size,
- (long) (thr->valstack_bottom - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (void *) thr->valstack, (void *) thr->valstack_end,
- (void *) thr->valstack_bottom, (void *) thr->valstack_top));
-
- /* Init newly allocated slots (only). */
- p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
- while (p < thr->valstack_end) {
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
+
+ DUK_D(DUK_DPRINT("resized valstack %lu -> %lu elements (%lu -> %lu bytes): "
+ "base=%p -> %p, bottom=%p -> %p (%ld), top=%p -> %p (%ld), "
+ "end=%p -> %p (%ld), alloc_end=%p -> %p (%ld);"
+ " tv_prev_alloc_end=%p (-> %ld inits; <0 means shrink)",
+ (unsigned long) (pre_alloc_end - pre_valstack),
+ (unsigned long) new_size,
+ (unsigned long) ((duk_uint8_t *) pre_alloc_end - (duk_uint8_t *) pre_valstack),
+ (unsigned long) new_alloc_size,
+ (void *) pre_valstack, (void *) thr->valstack,
+ (void *) pre_bottom, (void *) thr->valstack_bottom, (long) (thr->valstack_bottom - thr->valstack),
+ (void *) pre_top, (void *) thr->valstack_top, (long) (thr->valstack_top - thr->valstack),
+ (void *) pre_end, (void *) thr->valstack_end, (long) (thr->valstack_end - thr->valstack),
+ (void *) pre_alloc_end, (void *) thr->valstack_alloc_end, (long) (thr->valstack_alloc_end - thr->valstack),
+ (void *) tv_prev_alloc_end, (long) (thr->valstack_alloc_end - tv_prev_alloc_end)));
+
+ /* If allocation grew, init any new slots to 'undefined'. */
+ p = tv_prev_alloc_end;
+ while (p < thr->valstack_alloc_end) {
/* Never executed if new size is smaller. */
DUK_TVAL_SET_UNDEFINED(p);
p++;
@@ -17406,7 +17860,7 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
/* Assert for value stack initialization policy. */
#if defined(DUK_USE_ASSERTIONS)
p = thr->valstack_top;
- while (p < thr->valstack_end) {
+ while (p < thr->valstack_alloc_end) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
p++;
}
@@ -17415,229 +17869,257 @@ DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size)
return 1;
}
-DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_do_resize(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t old_size;
+DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, duk_size_t min_bytes, duk_bool_t throw_on_error) {
+ duk_size_t min_size;
duk_size_t new_size;
- duk_bool_t is_shrink;
- duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT);
- duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(min_bytes / sizeof(duk_tval) * sizeof(duk_tval) == min_bytes);
+ min_size = min_bytes / sizeof(duk_tval); /* from bytes to slots */
-#if defined(DUK_USE_PREFER_SIZE)
- old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
+#if defined(DUK_USE_VALSTACK_GROW_SHIFT)
+ /* New size is minimum size plus a proportional slack, e.g. shift of
+ * 2 means a 25% slack.
+ */
+ new_size = min_size + (min_size >> DUK_USE_VALSTACK_GROW_SHIFT);
#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- old_size = thr->valstack_size;
+ /* New size is tight with no slack. This is sometimes preferred in
+ * low memory environments.
+ */
+ new_size = min_size;
#endif
- if (min_new_size <= old_size) {
- is_shrink = 1;
- } else {
- is_shrink = 0;
- }
-
- new_size = min_new_size;
- if (!compact_flag) {
- if (is_shrink) {
- /* shrink case; leave some spare */
- new_size += DUK_VALSTACK_SHRINK_SPARE;
- }
-
- /* round up roughly to next 'grow step' */
- new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
- }
-
- DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)",
- (const char *) (new_size > old_size ? "grow" : "shrink"),
- (unsigned long) old_size, (unsigned long) new_size,
- (unsigned long) min_new_size));
-
- if (DUK_UNLIKELY(new_size > thr->valstack_max)) {
+ if (DUK_UNLIKELY(new_size > DUK_USE_VALSTACK_LIMIT || new_size < min_size /*wrap*/)) {
/* Note: may be triggered even if minimal new_size would not reach the limit,
- * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account).
+ * plan limit accordingly.
*/
- if (throw_flag) {
+ if (throw_on_error) {
DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
- } else {
- return 0;
}
+ return 0;
}
- /*
- * When resizing the valstack, a mark-and-sweep may be triggered for
- * the allocation of the new valstack. If the mark-and-sweep needs
- * to use our thread for something, it may cause *the same valstack*
- * to be resized recursively. This happens e.g. when mark-and-sweep
- * finalizers are called. This is taken into account carefully in
- * duk__resize_valstack().
- *
- * 'new_size' is known to be <= valstack_max, which ensures that
- * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
- */
-
- if (DUK_UNLIKELY(!duk__resize_valstack(ctx, new_size))) {
- if (is_shrink) {
- DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore"));
- return 1;
- }
-
- DUK_DD(DUK_DDPRINT("valstack resize failed"));
-
- if (throw_flag) {
+ if (duk__resize_valstack(thr, new_size) == 0) {
+ if (throw_on_error) {
DUK_ERROR_ALLOC_FAILED(thr);
- } else {
- return 0;
}
+ return 0;
}
- DUK_DDD(DUK_DDDPRINT("valstack resize successful"));
+ thr->valstack_end = thr->valstack + min_size;
+ DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
+
return 1;
}
-DUK_INTERNAL duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t old_size;
+/* Hot, inlined value stack grow check. Because value stack almost never
+ * grows, the actual resize call is in a NOINLINE helper.
+ */
+DUK_INTERNAL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes) {
+ duk_tval *tv;
- DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, "
- "curr_bottom=%ld, flags=%lx",
- (unsigned long) min_new_size,
- (long) (thr->valstack_end - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (long) (thr->valstack_bottom - thr->valstack),
- (unsigned long) flags));
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
+ if (DUK_LIKELY(thr->valstack_end >= tv)) {
+ return;
+ }
+ if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
+ /* Values in [valstack_top,valstack_alloc_end[ are initialized
+ * to 'undefined' so we can just move the end pointer.
+ */
+ thr->valstack_end = tv;
+ return;
+ }
+ (void) duk__valstack_grow(thr, min_bytes, 1 /*throw_on_error*/);
+}
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+/* Hot, inlined value stack grow check which doesn't throw. */
+DUK_INTERNAL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes) {
+ duk_tval *tv;
-#if defined(DUK_USE_PREFER_SIZE)
- old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
+ if (DUK_LIKELY(thr->valstack_end >= tv)) {
+ return 1;
+ }
+ if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
+ thr->valstack_end = tv;
+ return 1;
+ }
+ return duk__valstack_grow(thr, min_bytes, 0 /*throw_on_error*/);
+}
+
+/* Value stack shrink check, called from mark-and-sweep. */
+DUK_INTERNAL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug) {
+ duk_size_t alloc_bytes;
+ duk_size_t reserve_bytes;
+ duk_size_t shrink_bytes;
+
+ alloc_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
+ reserve_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ DUK_ASSERT(alloc_bytes >= reserve_bytes);
+
+ /* We're free to shrink the value stack allocation down to
+ * reserve_bytes but not more. If 'snug' (emergency GC)
+ * shrink whatever we can. Otherwise only shrink if the new
+ * size would be considerably smaller.
+ */
+
+#if defined(DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT)
+ if (snug) {
+ shrink_bytes = reserve_bytes;
+ } else {
+ duk_size_t proportion, slack;
+
+ /* Require that value stack shrinks by at least X% of its
+ * current size. For example, shift of 2 means at least
+ * 25%. The proportion is computed as bytes and may not
+ * be a multiple of sizeof(duk_tval); that's OK here.
+ */
+ proportion = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT;
+ if (alloc_bytes - reserve_bytes < proportion) {
+ /* Too little would be freed, do nothing. */
+ return;
+ }
+
+ /* Keep a slack after shrinking. The slack is again a
+ * proportion of the current size (the proportion should
+ * of course be smaller than the check proportion above).
+ */
+#if defined(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT)
+ DUK_ASSERT(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT > DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT);
+ slack = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT;
#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- old_size = thr->valstack_size;
+ slack = 0;
#endif
+ shrink_bytes = reserve_bytes +
+ slack / sizeof(duk_tval) * sizeof(duk_tval); /* multiple of duk_tval */
+ }
+#else /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
+ /* Always snug, useful in some low memory environments. */
+ DUK_UNREF(snug);
+ shrink_bytes = reserve_bytes;
+#endif /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
- if (DUK_LIKELY(min_new_size <= old_size)) {
- if (DUK_LIKELY((flags & DUK_VSRESIZE_FLAG_SHRINK) == 0 ||
- old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD)) {
- DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack"));
- return 1;
- }
+ DUK_D(DUK_DPRINT("valstack shrink check: alloc_bytes=%ld, reserve_bytes=%ld, shrink_bytes=%ld (unvalidated)",
+ (long) alloc_bytes, (long) reserve_bytes, (long) shrink_bytes));
+ DUK_ASSERT(shrink_bytes >= reserve_bytes);
+ if (shrink_bytes >= alloc_bytes) {
+ /* Skip if shrink target is same as current one (or higher,
+ * though that shouldn't happen in practice).
+ */
+ return;
}
+ DUK_ASSERT(shrink_bytes / sizeof(duk_tval) * sizeof(duk_tval) == shrink_bytes);
+
+ DUK_D(DUK_DPRINT("valstack shrink check: decided to shrink, snug: %ld", (long) snug));
- return duk__valstack_do_resize(ctx, min_new_size, flags);
+ duk__resize_valstack(thr, shrink_bytes / sizeof(duk_tval));
}
-DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
+DUK_EXTERNAL duk_bool_t duk_check_stack(duk_hthread *thr, duk_idx_t extra) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
+ if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
+ if (extra < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ extra = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ extra = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
+ return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
}
-DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
+DUK_EXTERNAL void duk_require_stack(duk_hthread *thr, duk_idx_t extra) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
+ if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
+ if (extra < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ extra = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ extra = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
+ duk_valstack_grow_check_throw(thr, min_new_bytes);
}
-DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_size_t min_new_size;
+DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_hthread *thr, duk_idx_t top) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
+ if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
+ if (top < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ top = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ top = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
+ DUK_ASSERT(top >= 0);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
+ return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
}
-DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_size_t min_new_size;
+DUK_EXTERNAL void duk_require_stack_top(duk_hthread *thr, duk_idx_t top) {
+ duk_size_t min_new_bytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
+ if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
+ if (top < 0) {
+ /* Clamping to zero makes the API more robust to calling code
+ * calculation errors.
+ */
+ top = 0;
+ } else {
+ /* Cause grow check to fail without wrapping arithmetic. */
+ top = DUK_USE_VALSTACK_LIMIT;
+ }
}
- min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_ASSERT(top >= 0);
+ min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
+ sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
+ duk_valstack_grow_check_throw(thr, min_new_bytes);
}
/*
* Basic stack manipulation: swap, dup, insert, replace, etc
*/
-DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
+DUK_EXTERNAL void duk_swap(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1;
duk_tval *tv2;
duk_tval tv_tmp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, idx1);
+ tv1 = duk_require_tval(thr, idx1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, idx2);
+ tv2 = duk_require_tval(thr, idx2);
DUK_ASSERT(tv2 != NULL);
/* If tv1==tv2 this is a NOP, no check is needed */
@@ -17646,22 +18128,20 @@ DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
}
-DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_swap_top(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_swap(ctx, idx, -1);
+ duk_swap(thr, idx, -1);
}
-DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_idx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx) {
duk_tval *tv_from;
duk_tval *tv_to;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
- tv_from = duk_require_tval(ctx, from_idx);
+ tv_from = duk_require_tval(thr, from_idx);
tv_to = thr->valstack_top++;
DUK_ASSERT(tv_from != NULL);
DUK_ASSERT(tv_to != NULL);
@@ -17669,16 +18149,14 @@ DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_idx) {
DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
}
-DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
+DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) {
#if defined(DUK_USE_PREFER_SIZE)
- duk_dup(ctx, -1);
+ duk_dup(thr, -1);
#else
- duk_hthread *thr;
duk_tval *tv_from;
duk_tval *tv_to;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) {
@@ -17694,36 +18172,42 @@ DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
#endif
}
-DUK_INTERNAL void duk_dup_0(duk_context *ctx) {
- duk_dup(ctx, 0);
+DUK_INTERNAL void duk_dup_0(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 0);
}
-DUK_INTERNAL void duk_dup_1(duk_context *ctx) {
- duk_dup(ctx, 1);
+DUK_INTERNAL void duk_dup_1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 1);
}
-DUK_INTERNAL void duk_dup_2(duk_context *ctx) {
- duk_dup(ctx, 2);
+DUK_INTERNAL void duk_dup_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, 2);
}
-DUK_INTERNAL void duk_dup_m2(duk_context *ctx) {
- duk_dup(ctx, -2);
+DUK_INTERNAL void duk_dup_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -2);
}
-DUK_INTERNAL void duk_dup_m3(duk_context *ctx) {
- duk_dup(ctx, -3);
+DUK_INTERNAL void duk_dup_m3(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -3);
}
-DUK_INTERNAL void duk_dup_m4(duk_context *ctx) {
- duk_dup(ctx, -4);
+DUK_INTERNAL void duk_dup_m4(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_dup(thr, -4);
}
-DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_idx) {
+DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) {
duk_tval *p;
duk_tval *q;
duk_tval tv_tmp;
duk_size_t nbytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p = duk_require_tval(ctx, to_idx);
+ p = duk_require_tval(thr, to_idx);
DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
+ q = duk_require_tval(thr, -1);
DUK_ASSERT(q != NULL);
DUK_ASSERT(q >= p);
@@ -17753,21 +18237,43 @@ DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_idx) {
}
}
-DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(idx >= 0); /* Doesn't support negative indices. */
+
+ duk_push_undefined(thr);
+ duk_insert(thr, idx);
+}
+
+DUK_INTERNAL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+ duk_tval *tv, *tv_end;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(idx >= 0); /* Doesn't support negative indices or count. */
+ DUK_ASSERT(count >= 0);
+
+ tv = duk_reserve_gap(thr, idx, count);
+ tv_end = tv + count;
+ while (tv != tv_end) {
+ DUK_TVAL_SET_UNDEFINED(tv);
+ tv++;
+ }
+}
+
+DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx) {
duk_tval *tv1;
duk_tval *tv2;
duk_tval tv_tmp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, -1);
+ tv1 = duk_require_tval(thr, -1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_idx);
+ tv2 = duk_require_tval(thr, to_idx);
DUK_ASSERT(tv2 != NULL);
/* For tv1 == tv2, both pointing to stack top, the end result
- * is same as duk_pop(ctx).
+ * is same as duk_pop(thr).
*/
DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
DUK_TVAL_SET_TVAL(tv2, tv1);
@@ -17776,25 +18282,22 @@ DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_idx) {
DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
}
-DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_idx, duk_idx_t to_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_copy(duk_hthread *thr, duk_idx_t from_idx, duk_idx_t to_idx) {
duk_tval *tv1;
duk_tval *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr); /* w/o refcounting */
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_require_tval(ctx, from_idx);
+ tv1 = duk_require_tval(thr, from_idx);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_idx);
+ tv2 = duk_require_tval(thr, to_idx);
DUK_ASSERT(tv2 != NULL);
/* For tv1 == tv2, this is a no-op (no explicit check needed). */
DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
}
-DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) {
duk_tval *p;
duk_tval *q;
#if defined(DUK_USE_REFERENCE_COUNTING)
@@ -17802,11 +18305,11 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t idx) {
#endif
duk_size_t nbytes;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- p = duk_require_tval(ctx, idx);
+ p = duk_require_tval(thr, idx);
DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
+ q = duk_require_tval(thr, -1);
DUK_ASSERT(q != NULL);
DUK_ASSERT(q >= p);
@@ -17833,17 +18336,74 @@ DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t idx) {
#endif
}
-DUK_INTERNAL_DECL void duk_remove_m2(duk_context *ctx) {
- duk_remove(ctx, -2);
+DUK_INTERNAL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove(thr, idx); /* XXX: no optimization for now */
+}
+
+DUK_INTERNAL void duk_remove_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove(thr, -2);
+}
+
+DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+#if defined(DUK_USE_PREFER_SIZE)
+ /* XXX: maybe too slow even when preferring size? */
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(idx >= 0);
+
+ while (count-- > 0) {
+ duk_remove(thr, idx);
+ }
+#else /* DUK_USE_PREFER_SIZE */
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_tval *tv_newtop;
+ duk_tval *tv;
+ duk_size_t bytes;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(idx >= 0);
+
+ tv_dst = thr->valstack_bottom + idx;
+ DUK_ASSERT(tv_dst <= thr->valstack_top);
+ tv_src = tv_dst + count;
+ DUK_ASSERT(tv_src <= thr->valstack_top);
+ bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
+
+ for (tv = tv_dst; tv < tv_src; tv++) {
+ DUK_TVAL_DECREF_NORZ(thr, tv);
+ }
+
+ DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, bytes);
+
+ tv_newtop = thr->valstack_top - count;
+ for (tv = tv_newtop; tv < thr->valstack_top; tv++) {
+ DUK_TVAL_SET_UNDEFINED(tv);
+ }
+ thr->valstack_top = tv_newtop;
+
+ /* When not preferring size, only NORZ macros are used; caller
+ * is expected to DUK_REFZERO_CHECK().
+ */
+#endif /* DUK_USE_PREFER_SIZE */
+}
+
+DUK_INTERNAL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_remove_n(thr, idx, count); /* XXX: no optimization for now */
}
/*
* Stack slice primitives
*/
-DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) {
- duk_hthread *to_thr = (duk_hthread *) to_ctx;
- duk_hthread *from_thr = (duk_hthread *) from_ctx;
+DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, duk_idx_t count, duk_bool_t is_copy) {
void *src;
duk_size_t nbytes;
duk_tval *p;
@@ -17851,23 +18411,25 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
/* XXX: several pointer comparison issues here */
- DUK_ASSERT_CTX_VALID(to_ctx);
- DUK_ASSERT_CTX_VALID(from_ctx);
- DUK_ASSERT(to_ctx != NULL);
- DUK_ASSERT(from_ctx != NULL);
+ DUK_ASSERT_API_ENTRY(to_thr);
+ DUK_ASSERT_CTX_VALID(to_thr);
+ DUK_ASSERT_CTX_VALID(from_thr);
+ DUK_ASSERT(to_thr->heap == from_thr->heap);
- if (DUK_UNLIKELY(to_ctx == from_ctx)) {
+ if (DUK_UNLIKELY(to_thr == from_thr)) {
DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT);
return;
}
- if (DUK_UNLIKELY((count < 0) ||
- (count > (duk_idx_t) to_thr->valstack_max))) {
- /* Maximum value check ensures 'nbytes' won't wrap below. */
+ if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) {
+ /* Maximum value check ensures 'nbytes' won't wrap below.
+ * Also handles negative count.
+ */
DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
return;
}
+ DUK_ASSERT(count >= 0);
- nbytes = sizeof(duk_tval) * count;
+ nbytes = sizeof(duk_tval) * (duk_size_t) count;
if (DUK_UNLIKELY(nbytes == 0)) {
return;
}
@@ -17880,7 +18442,7 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
}
- /* copy values (no overlap even if to_ctx == from_ctx; that's not
+ /* copy values (no overlap even if to_thr == from_thr; that's not
* allowed now anyway)
*/
DUK_ASSERT(nbytes > 0);
@@ -17910,43 +18472,72 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx,
}
}
+/* Internal helper: reserve a gap of 'count' elements at 'idx_base' and return a
+ * pointer to the gap. Values in the gap are garbage and MUST be initialized by
+ * the caller before any side effects may occur. The caller must ensure there's
+ * enough stack reserve for 'count' values.
+ */
+DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count) {
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+ duk_size_t gap_bytes;
+ duk_size_t copy_bytes;
+
+ /* Caller is responsible for ensuring there's enough preallocated
+ * value stack.
+ */
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack_top) >= (duk_size_t) count);
+
+ tv_src = thr->valstack_bottom + idx_base;
+ gap_bytes = (duk_size_t) count * sizeof(duk_tval);
+ tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes);
+ copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
+ thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes);
+ DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, copy_bytes);
+
+ /* Values in the gap are left as garbage: caller must fill them in
+ * and INCREF them before any side effects.
+ */
+ return tv_src;
+}
+
/*
* Get/opt/require
*/
-DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED);
}
}
-DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL);
}
}
-DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) {
+DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
duk_bool_t ret;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BOOLEAN(tv)) {
ret = DUK_TVAL_GET_BOOLEAN(tv);
@@ -17959,26 +18550,25 @@ DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_context *ctx, du
return ret;
}
-DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk__get_boolean_raw(ctx, idx, 0); /* default: false */
+ return duk__get_boolean_raw(thr, idx, 0); /* default: false */
}
-DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk__get_boolean_raw(ctx, idx, def_value);
+ return duk__get_boolean_raw(thr, idx, def_value);
}
-DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_bool_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) {
ret = DUK_TVAL_GET_BOOLEAN(tv);
@@ -17989,22 +18579,22 @@ DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) {
}
}
-DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_context *ctx, duk_idx_t idx, duk_bool_t def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_value;
}
- return duk_require_boolean(ctx, idx);
+ return duk_require_boolean(thr, idx);
}
-DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) {
+DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
duk_double_union ret;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv)) {
@@ -18027,22 +18617,23 @@ DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_context *ctx, d
return ret.d;
}
-DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) {
- return duk__get_number_raw(ctx, idx, DUK_DOUBLE_NAN); /* default: NaN */
+DUK_EXTERNAL duk_double_t duk_get_number(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_number_raw(thr, idx, DUK_DOUBLE_NAN); /* default: NaN */
}
-DUK_EXTERNAL duk_double_t duk_get_number_default(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) {
- return duk__get_number_raw(ctx, idx, def_value);
+DUK_EXTERNAL duk_double_t duk_get_number_default(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_number_raw(thr, idx, def_value);
}
-DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_double_union ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
@@ -18058,78 +18649,78 @@ DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) {
return ret.d;
}
-DUK_EXTERNAL duk_double_t duk_opt_number(duk_context *ctx, duk_idx_t idx, duk_double_t def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_double_t duk_opt_number(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
/* User provided default is not NaN normalized. */
return def_value;
}
- return duk_require_number(ctx, idx);
+ return duk_require_number(thr, idx);
}
-DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/);
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_uint_t duk_get_uint(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/);
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_int_t duk_get_int_default(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_int_t duk_get_int_default(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_int_t) duk__api_coerce_d2i(ctx, idx, def_value, 0 /*require*/);
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, def_value, 0 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, def_value, 0 /*require*/);
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, def_value, 0 /*require*/);
}
-DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_int_t duk_require_int(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 1 /*require*/);
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 1 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_uint_t duk_require_uint(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 1 /*require*/);
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 1 /*require*/);
}
-DUK_EXTERNAL duk_int_t duk_opt_int(duk_context *ctx, duk_idx_t idx, duk_int_t def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_int_t duk_opt_int(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_value;
}
- return duk_require_int(ctx, idx);
+ return duk_require_int(thr, idx);
}
-DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_context *ctx, duk_idx_t idx, duk_uint_t def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_value;
}
- return duk_require_uint(ctx, idx);
+ return duk_require_uint(thr, idx);
}
-DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
+DUK_EXTERNAL const char *duk_get_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
duk_hstring *h;
const char *ret;
duk_size_t len;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hstring(ctx, idx);
+ h = duk_get_hstring(thr, idx);
if (h != NULL) {
len = DUK_HSTRING_GET_BYTELEN(h);
ret = (const char *) DUK_HSTRING_GET_DATA(h);
@@ -18144,12 +18735,12 @@ DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_si
return ret;
}
-DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
+DUK_EXTERNAL const char *duk_require_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_require_hstring(ctx, idx);
+ h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
if (out_len) {
*out_len = DUK_HSTRING_GET_BYTELEN(h);
@@ -18157,12 +18748,12 @@ DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, du
return (const char *) DUK_HSTRING_GET_DATA(h);
}
-DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
+DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_require_hstring_notsymbol(ctx, idx);
+ h = duk_require_hstring_notsymbol(thr, idx);
DUK_ASSERT(h != NULL);
if (out_len) {
*out_len = DUK_HSTRING_GET_BYTELEN(h);
@@ -18170,12 +18761,12 @@ DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx
return (const char *) DUK_HSTRING_GET_DATA(h);
}
-DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL const char *duk_get_string(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hstring(ctx, idx);
+ h = duk_get_hstring(thr, idx);
if (h != NULL) {
return (const char *) DUK_HSTRING_GET_DATA(h);
} else {
@@ -18183,35 +18774,35 @@ DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) {
}
}
-DUK_EXTERNAL const char *duk_opt_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_opt_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
if (out_len != NULL) {
*out_len = def_len;
}
return def_ptr;
}
- return duk_require_lstring(ctx, idx, out_len);
+ return duk_require_lstring(thr, idx, out_len);
}
-DUK_EXTERNAL const char *duk_opt_string(duk_context *ctx, duk_idx_t idx, const char *def_ptr) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_opt_string(duk_hthread *thr, duk_idx_t idx, const char *def_ptr) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_ptr;
}
- return duk_require_string(ctx, idx);
+ return duk_require_string(thr, idx);
}
-DUK_EXTERNAL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
+DUK_EXTERNAL const char *duk_get_lstring_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
duk_hstring *h;
const char *ret;
duk_size_t len;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hstring(ctx, idx);
+ h = duk_get_hstring(thr, idx);
if (h != NULL) {
len = DUK_HSTRING_GET_BYTELEN(h);
ret = (const char *) DUK_HSTRING_GET_DATA(h);
@@ -18226,12 +18817,12 @@ DUK_EXTERNAL const char *duk_get_lstring_default(duk_context *ctx, duk_idx_t idx
return ret;
}
-DUK_EXTERNAL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx, const char *def_value) {
+DUK_EXTERNAL const char *duk_get_string_default(duk_hthread *thr, duk_idx_t idx, const char *def_value) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hstring(ctx, idx);
+ h = duk_get_hstring(thr, idx);
if (h != NULL) {
return (const char *) DUK_HSTRING_GET_DATA(h);
} else {
@@ -18239,12 +18830,12 @@ DUK_EXTERNAL const char *duk_get_string_default(duk_context *ctx, duk_idx_t idx,
}
}
-DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hstring_notsymbol(ctx, idx);
+ h = duk_get_hstring_notsymbol(thr, idx);
if (h) {
return (const char *) DUK_HSTRING_GET_DATA(h);
} else {
@@ -18252,29 +18843,41 @@ DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t id
}
}
-DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_require_string(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk_require_lstring(ctx, idx, NULL);
+ return duk_require_lstring(thr, idx, NULL);
}
-DUK_INTERNAL const char *duk_require_string_notsymbol(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_require_hstring_notsymbol(ctx, idx);
+ h = duk_require_hstring_notsymbol(thr, idx);
DUK_ASSERT(h != NULL);
return (const char *) DUK_HSTRING_GET_DATA(h);
}
-DUK_LOCAL void *duk__get_pointer_raw(duk_context *ctx, duk_idx_t idx, void *def_value) {
+DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ DUK_ASSERT(tv != NULL);
+ if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ }
+}
+
+DUK_LOCAL void *duk__get_pointer_raw(duk_hthread *thr, duk_idx_t idx, void *def_value) {
duk_tval *tv;
void *p;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (!DUK_TVAL_IS_POINTER(tv)) {
return def_value;
@@ -18284,34 +18887,35 @@ DUK_LOCAL void *duk__get_pointer_raw(duk_context *ctx, duk_idx_t idx, void *def_
return p;
}
-DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) {
- return duk__get_pointer_raw(ctx, idx, NULL /*def_value*/);
+DUK_EXTERNAL void *duk_get_pointer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_pointer_raw(thr, idx, NULL /*def_value*/);
}
-DUK_EXTERNAL void *duk_opt_pointer(duk_context *ctx, duk_idx_t idx, void *def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_opt_pointer(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_value;
}
- return duk_require_pointer(ctx, idx);
+ return duk_require_pointer(thr, idx);
}
-DUK_EXTERNAL void *duk_get_pointer_default(duk_context *ctx, duk_idx_t idx, void *def_value) {
- return duk__get_pointer_raw(ctx, idx, def_value);
+DUK_EXTERNAL void *duk_get_pointer_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_pointer_raw(thr, idx, def_value);
}
-DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *p;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Note: here we must be wary of the fact that a pointer may be
* valid and be a NULL.
*/
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER);
@@ -18321,13 +18925,13 @@ DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) {
}
#if 0 /*unused*/
-DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_heaphdr *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
return NULL;
@@ -18339,21 +18943,19 @@ DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx) {
}
#endif
-DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) {
duk_hbuffer *h;
void *ret;
duk_size_t len;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_CTX_VALID(thr);
if (out_size != NULL) {
*out_size = 0;
}
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) {
h = DUK_TVAL_GET_BUFFER(tv);
@@ -18375,34 +18977,34 @@ DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size
return ret;
}
-DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_get_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/);
+ return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/);
}
-DUK_EXTERNAL void *duk_opt_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_opt_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
if (out_size != NULL) {
*out_size = def_size;
}
return def_ptr;
}
- return duk_require_buffer(ctx, idx, out_size);
+ return duk_require_buffer(thr, idx, out_size);
}
-DUK_EXTERNAL void *duk_get_buffer_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_get_buffer_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk__get_buffer_helper(ctx, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/);
+ return duk__get_buffer_helper(thr, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/);
}
-DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_require_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk__get_buffer_helper(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/);
+ return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/);
}
/* Get the active buffer data area for a plain buffer or a buffer object.
@@ -18410,12 +19012,10 @@ DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_
* have a NULL data pointer when its size is zero, the optional 'out_isbuffer'
* argument allows caller to detect this reliably.
*/
-DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
if (out_isbuffer != NULL) {
*out_isbuffer = 0;
@@ -18424,7 +19024,7 @@ DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_
*out_size = def_size;
}
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
@@ -18473,28 +19073,31 @@ DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_
return def_ptr;
}
-DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
- return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL);
+DUK_EXTERNAL void *duk_get_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL);
}
-DUK_EXTERNAL void *duk_get_buffer_data_default(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
- return duk_get_buffer_data_raw(ctx, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL);
+DUK_EXTERNAL void *duk_get_buffer_data_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL);
}
-DUK_EXTERNAL void *duk_opt_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_opt_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
if (out_size != NULL) {
*out_size = def_size;
}
return def_ptr;
}
- return duk_require_buffer_data(ctx, idx, out_size);
+ return duk_require_buffer_data(thr, idx, out_size);
}
-DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
- return duk_get_buffer_data_raw(ctx, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL);
+DUK_EXTERNAL void *duk_require_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL);
}
/* Raw helper for getting a value from the stack, checking its tag.
@@ -18502,13 +19105,13 @@ DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_
* tag in the packed representation.
*/
-DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag) {
+DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag) {
duk_tval *tv;
duk_heaphdr *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_GET_TAG(tv) != tag) {
return (duk_heaphdr *) NULL;
@@ -18520,121 +19123,161 @@ DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t i
}
-DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t idx) {
- return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
+DUK_INTERNAL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
}
-DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) {
- duk_hstring *res = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
- if (DUK_UNLIKELY(res && DUK_HSTRING_HAS_SYMBOL(res))) {
+DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ duk_hstring *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
+ if (DUK_UNLIKELY(h && DUK_HSTRING_HAS_SYMBOL(h))) {
return NULL;
}
- return res;
+ return h;
}
-DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
if (DUK_UNLIKELY(h == NULL)) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
}
return h;
}
-DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
}
return h;
}
-DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t idx) {
- return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
}
-DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *h;
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(h == NULL)) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "object", DUK_STR_NOT_OBJECT);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
}
return h;
}
-DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t idx) {
- return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER);
+DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
}
-DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) {
duk_hbuffer *h;
- h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
if (DUK_UNLIKELY(h == NULL)) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "buffer", DUK_STR_NOT_BUFFER);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
}
return h;
}
-DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) {
h = NULL;
}
return (duk_hthread *) h;
}
-DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD);
}
return (duk_hthread *) h;
}
-DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) {
h = NULL;
}
return (duk_hcompfunc *) h;
}
-DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC);
}
return (duk_hcompfunc *) h;
}
-DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) {
h = NULL;
}
return (duk_hnatfunc *) h;
}
-DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ duk_hobject *h;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
}
return (duk_hnatfunc *) h;
}
-DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_c_function duk_get_c_function(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hobject *h;
duk_hnatfunc *f;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
return NULL;
@@ -18651,21 +19294,21 @@ DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx)
return f->func;
}
-DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_value;
}
- return duk_require_c_function(ctx, idx);
+ return duk_require_c_function(thr, idx);
}
-DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx_t idx, duk_c_function def_value) {
+DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
duk_c_function ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_get_c_function(ctx, idx);
+ ret = duk_get_c_function(thr, idx);
if (ret != NULL) {
return ret;
}
@@ -18673,62 +19316,64 @@ DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_context *ctx, duk_idx
return def_value;
}
-DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t idx) {
duk_c_function ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_get_c_function(ctx, idx);
+ ret = duk_get_c_function(thr, idx);
if (DUK_UNLIKELY(!ret)) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
}
return ret;
}
-DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t idx) {
- if (DUK_UNLIKELY(!duk_is_function(ctx, idx))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "function", DUK_STR_NOT_FUNCTION);
+DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ if (DUK_UNLIKELY(!duk_is_function(thr, idx))) {
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION);
}
}
-DUK_INTERNAL_DECL void duk_require_constructable(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *h;
- h = duk_require_hobject_accept_mask(ctx, idx, DUK_TYPE_MASK_LIGHTFUNC);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC);
if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
}
/* Lightfuncs (h == NULL) are constructable. */
}
-DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_hthread *duk_get_context(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_context *) duk_get_hthread(ctx, idx);
+ return duk_get_hthread(thr, idx);
}
-DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_hthread *duk_require_context(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_context *) duk_require_hthread(ctx, idx);
+ return duk_require_hthread(thr, idx);
}
-DUK_EXTERNAL duk_context *duk_opt_context(duk_context *ctx, duk_idx_t idx, duk_context *def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_hthread *duk_opt_context(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_value;
}
- return duk_require_context(ctx, idx);
+ return duk_require_context(thr, idx);
}
-DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx_t idx, duk_context *def_value) {
- duk_context *ret;
+DUK_EXTERNAL duk_hthread *duk_get_context_default(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
+ duk_hthread *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_get_context(ctx, idx);
+ ret = duk_get_context(thr, idx);
if (ret != NULL) {
return ret;
}
@@ -18736,13 +19381,13 @@ DUK_EXTERNAL_DECL duk_context *duk_get_context_default(duk_context *ctx, duk_idx
return def_value;
}
-DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL void *duk_get_heapptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
return (void *) NULL;
@@ -18753,21 +19398,21 @@ DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) {
return ret;
}
-DUK_EXTERNAL void *duk_opt_heapptr(duk_context *ctx, duk_idx_t idx, void *def_value) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void *duk_opt_heapptr(duk_hthread *thr, duk_idx_t idx, void *def_value) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
+ if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
return def_value;
}
- return duk_require_heapptr(ctx, idx);
+ return duk_require_heapptr(thr, idx);
}
-DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx, void *def_value) {
+DUK_EXTERNAL void *duk_get_heapptr_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- ret = duk_get_heapptr(ctx, idx);
+ ret = duk_get_heapptr(thr, idx);
if (ret != NULL) {
return ret;
}
@@ -18775,14 +19420,13 @@ DUK_EXTERNAL_DECL void *duk_get_heapptr_default(duk_context *ctx, duk_idx_t idx,
return def_value;
}
-DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE);
@@ -18794,22 +19438,22 @@ DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) {
}
/* Internal helper for getting/requiring a duk_hobject with possible promotion. */
-DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
+DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
duk_uint_t val_mask;
duk_hobject *res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- res = duk_get_hobject(ctx, idx); /* common case, not promoted */
+ res = duk_get_hobject(thr, idx); /* common case, not promoted */
if (DUK_LIKELY(res != NULL)) {
DUK_ASSERT(res != NULL);
return res;
}
- val_mask = duk_get_type_mask(ctx, idx);
+ val_mask = duk_get_type_mask(thr, idx);
if (val_mask & type_mask) {
if (type_mask & DUK_TYPE_MASK_PROMOTE) {
- res = duk_to_hobject(ctx, idx);
+ res = duk_to_hobject(thr, idx);
DUK_ASSERT(res != NULL);
return res;
} else {
@@ -18818,7 +19462,7 @@ DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_context *ctx, duk_i
}
if (type_mask & DUK_TYPE_MASK_THROW) {
- DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "object", DUK_STR_NOT_OBJECT);
+ DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
}
return NULL;
}
@@ -18830,48 +19474,49 @@ DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_context *ctx, duk_i
* Return value is NULL if value is neither an object nor a plain type allowed
* by the mask.
*/
-DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
- return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_PROMOTE);
+DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_PROMOTE);
}
/* Like duk_get_hobject_promote_mask() but throw a TypeError instead of
* returning a NULL.
*/
-DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
- return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE);
+DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE);
}
/* Require a duk_hobject * at 'idx'; if the value is not an object but matches the
* supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError.
*/
-DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
- return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_THROW);
+DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW);
}
-DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum) {
+DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(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 idx, duk_small_uint_t classnum) {
- duk_hthread *thr;
+DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
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, idx, DUK_TAG_OBJECT);
+ h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(!(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));
@@ -18882,12 +19527,12 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_i
return h;
}
-DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_size_t duk_get_length(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -18897,17 +19542,20 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
case DUK_TAG_POINTER:
return 0;
#if defined(DUK_USE_PREFER_SIZE)
- /* All of these types (besides object) have a virtual, non-configurable
- * .length property which is within size_t range so we can just look it
- * up without specific type checks.
+ /* String and buffer have a virtual non-configurable .length property
+ * which is within size_t range so it can be looked up without specific
+ * type checks. Lightfuncs inherit from %NativeFunctionPrototype%
+ * which provides an inherited .length accessor; it could be overwritten
+ * to produce unexpected types or values, but just number convert and
+ * duk_size_t cast for now.
*/
case DUK_TAG_STRING:
case DUK_TAG_BUFFER:
case DUK_TAG_LIGHTFUNC: {
duk_size_t ret;
- duk_get_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH);
- ret = (duk_size_t) duk_to_number_m1(ctx);
- duk_pop(ctx);
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ ret = (duk_size_t) duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
return ret;
}
#else /* DUK_USE_PREFER_SIZE */
@@ -18925,15 +19573,22 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
}
case DUK_TAG_LIGHTFUNC: {
- duk_small_uint_t lf_flags;
- lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
- return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ /* We could look up the length from the lightfunc duk_tval,
+ * but since Duktape 2.2 lightfunc .length comes from
+ * %NativeFunctionPrototype% which can be overridden, so
+ * look up the property explicitly.
+ */
+ duk_size_t ret;
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ ret = (duk_size_t) duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
+ return ret;
}
#endif /* DUK_USE_PREFER_SIZE */
case DUK_TAG_OBJECT: {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
- return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
+ return (duk_size_t) duk_hobject_get_length(thr, h);
}
#if defined(DUK_USE_FASTINT)
case DUK_TAG_FASTINT:
@@ -18952,17 +19607,16 @@ DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
*
* Used internally when we're 100% sure that a certain index is valid and
* contains an object of a certain type. For example, if we duk_push_object()
- * we can then safely duk_known_hobject(ctx, -1). These helpers just assert
+ * we can then safely duk_known_hobject(thr, -1). These helpers just assert
* for the index and type, and if the assumptions are not valid, memory unsafe
* behavior happens.
*/
-DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_heaphdr *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
if (idx < 0) {
tv = thr->valstack_top + idx;
} else {
@@ -18975,37 +19629,42 @@ DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_context *ctx, duk_idx_t idx) {
return h;
}
-DUK_INTERNAL duk_hstring *duk_known_hstring(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT(duk_get_hstring(ctx, idx) != NULL);
- return (duk_hstring *) duk__known_heaphdr(ctx, idx);
+DUK_INTERNAL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
+ return (duk_hstring *) duk__known_heaphdr(thr, idx);
}
-DUK_INTERNAL duk_hobject *duk_known_hobject(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT(duk_get_hobject(ctx, idx) != NULL);
- return (duk_hobject *) duk__known_heaphdr(ctx, idx);
+DUK_INTERNAL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hobject(thr, idx) != NULL);
+ return (duk_hobject *) duk__known_heaphdr(thr, idx);
}
-DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT(duk_get_hbuffer(ctx, idx) != NULL);
- return (duk_hbuffer *) duk__known_heaphdr(ctx, idx);
+DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hbuffer(thr, idx) != NULL);
+ return (duk_hbuffer *) duk__known_heaphdr(thr, idx);
}
-DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT(duk_get_hcompfunc(ctx, idx) != NULL);
- return (duk_hcompfunc *) duk__known_heaphdr(ctx, idx);
+DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hcompfunc(thr, idx) != NULL);
+ return (duk_hcompfunc *) duk__known_heaphdr(thr, idx);
}
-DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT(duk_get_hnatfunc(ctx, idx) != NULL);
- return (duk_hnatfunc *) duk__known_heaphdr(ctx, idx);
+DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_hnatfunc(thr, idx) != NULL);
+ return (duk_hnatfunc *) duk__known_heaphdr(thr, idx);
}
-DUK_EXTERNAL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_set_length(duk_hthread *thr, duk_idx_t idx, duk_size_t len) {
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_normalize_index(ctx, idx);
- duk_push_uint(ctx, (duk_uint_t) len);
- duk_put_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH);
+ idx = duk_normalize_index(thr, idx);
+ duk_push_uint(thr, (duk_uint_t) len);
+ duk_put_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
}
/*
@@ -19018,68 +19677,63 @@ DUK_EXTERNAL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len
/* E5 Section 8.12.8 */
-DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t idx, duk_small_int_t func_stridx) {
- if (duk_get_prop_stridx(ctx, idx, func_stridx)) {
+DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t func_stridx) {
+ if (duk_get_prop_stridx(thr, idx, func_stridx)) {
/* [ ... func ] */
- if (duk_is_callable(ctx, -1)) {
- duk_dup(ctx, idx); /* -> [ ... func this ] */
- duk_call_method(ctx, 0); /* -> [ ... retval ] */
- if (duk_is_primitive(ctx, -1)) {
- duk_replace(ctx, idx);
+ if (duk_is_callable(thr, -1)) {
+ duk_dup(thr, idx); /* -> [ ... func this ] */
+ duk_call_method(thr, 0); /* -> [ ... retval ] */
+ if (duk_is_primitive(thr, -1)) {
+ duk_replace(thr, idx);
return 1;
}
/* [ ... retval ]; popped below */
}
}
- duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */
+ duk_pop_unsafe(thr); /* [ ... func/retval ] -> [ ... ] */
return 0;
}
-DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_to_undefined(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
}
-DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
}
/* E5 Section 9.1 */
-DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hint) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
/* inline initializer for coercers[] is not allowed by old compilers like BCC */
- duk_small_int_t coercers[2];
+ duk_small_uint_t coercers[2];
duk_small_uint_t class_number;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
- idx = duk_require_normalize_index(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
- if (!duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_OBJECT |
+ if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER)) {
/* Any other values stay as is. */
- DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
- class_number = duk_get_class_number(ctx, idx);
+ class_number = duk_get_class_number(thr, idx);
/* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive()
* algorithm which consults value[@@toPrimitive] and avoids calling
@@ -19094,11 +19748,11 @@ DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hi
duk_hstring *h_str;
/* XXX: pretty awkward, index based API for internal value access? */
- h_obj = duk_known_hobject(ctx, idx);
+ h_obj = duk_known_hobject(thr, idx);
h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj);
if (h_str) {
- duk_push_hstring(ctx, h_str);
- duk_replace(ctx, idx);
+ duk_push_hstring(thr, h_str);
+ duk_replace(thr, idx);
return;
}
}
@@ -19127,13 +19781,13 @@ DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hi
coercers[1] = DUK_STRIDX_VALUE_OF;
}
- if (duk__defaultvalue_coerce_attempt(ctx, idx, coercers[0])) {
- DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */
+ if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[0])) {
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
- if (duk__defaultvalue_coerce_attempt(ctx, idx, coercers[1])) {
- DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */
+ if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[1])) {
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
@@ -19141,16 +19795,14 @@ DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hi
}
/* E5 Section 9.2 */
-DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_bool_t val;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
- tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
val = duk_js_toboolean(tv);
@@ -19162,43 +19814,64 @@ DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx) {
return val;
}
-DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: No need to normalize; the whole operation could be inlined here to
* avoid 'tv' re-lookup.
*/
- idx = duk_require_normalize_index(ctx, idx);
- tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */
/* ToNumber() may have side effects so must relookup 'tv'. */
- tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
return d;
}
-DUK_INTERNAL duk_double_t duk_to_number_m1(duk_context *ctx) {
- return duk_to_number(ctx, -1);
+DUK_INTERNAL duk_double_t duk_to_number_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_number(thr, -1);
}
-DUK_INTERNAL duk_double_t duk_to_number_m2(duk_context *ctx) {
- return duk_to_number(ctx, -2);
+DUK_INTERNAL duk_double_t duk_to_number_m2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_number(thr, -2);
}
-DUK_INTERNAL duk_double_t duk_to_number_tval(duk_context *ctx, duk_tval *tv) {
+DUK_INTERNAL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv) {
+#if defined(DUK_USE_PREFER_SIZE)
duk_double_t res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_tval(ctx, tv);
- res = duk_to_number(ctx, -1);
- duk_pop(ctx);
+ duk_push_tval(thr, tv);
+ res = duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
return res;
+#else
+ duk_double_t res;
+ duk_tval *tv_dst;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK__ASSERT_SPACE();
+
+ tv_dst = thr->valstack_top++;
+ DUK_TVAL_SET_TVAL(tv_dst, tv);
+ DUK_TVAL_INCREF(thr, tv_dst); /* decref not necessary */
+ res = duk_to_number_m1(thr); /* invalidates tv_dst */
+
+ tv_dst = --thr->valstack_top;
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_dst));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_dst)); /* plain number */
+ DUK_TVAL_SET_UNDEFINED(tv_dst); /* valstack init policy */
+
+ return res;
+#endif
}
/* XXX: combine all the integer conversions: they share everything
@@ -19207,14 +19880,13 @@ DUK_INTERNAL duk_double_t duk_to_number_tval(duk_context *ctx, duk_tval *tv) {
typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
-DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t idx, duk__toint_coercer coerce_func) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_hthread *thr, duk_idx_t idx, duk__toint_coercer coerce_func) {
duk_tval *tv;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
#if defined(DUK_USE_FASTINT)
@@ -19231,93 +19903,92 @@ DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t idx,
/* XXX: fastint? */
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
return d;
}
-DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx) {
/* Value coercion (in stack): ToInteger(), E5 Section 9.4,
* API return value coercion: custom.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger);
- return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*def_value*/, 0 /*require*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
+ return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_uint_t duk_to_uint(duk_hthread *thr, duk_idx_t idx) {
/* Value coercion (in stack): ToInteger(), E5 Section 9.4,
* API return value coercion: custom.
*/
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*def_value*/, 0 /*require*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
+ return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
}
-DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_int32_t duk_to_int32(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_int32_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_toint32(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
-DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint32_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_touint32(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
-DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint16_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
ret = duk_js_touint16(thr, tv);
/* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
return ret;
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* Special coercion for Uint8ClampedArray. */
-DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx) {
duk_double_t d;
duk_double_t t;
duk_uint8_t ret;
+ DUK_ASSERT_API_ENTRY(thr);
+
/* XXX: Simplify this algorithm, should be possible to come up with
* a shorter and faster algorithm by inspecting IEEE representation
* directly.
*/
- d = duk_to_number(ctx, idx);
+ d = duk_to_number(thr, idx);
if (d <= 0.0) {
return 0;
} else if (d >= 255) {
@@ -19342,41 +20013,41 @@ DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t idx) {
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- (void) duk_to_string(ctx, idx);
- DUK_ASSERT(duk_is_string(ctx, idx));
- return duk_require_lstring(ctx, idx, out_len);
+ (void) duk_to_string(thr, idx);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ return duk_require_lstring(thr, idx, out_len);
}
-DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx, void *udata) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_hthread *thr, void *udata) {
+ DUK_ASSERT_CTX_VALID(thr);
DUK_UNREF(udata);
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
return 1;
}
-DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_safe_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
/* We intentionally ignore the duk_safe_call() return value and only
* check the output type. This way we don't also need to check that
* the returned value is indeed a string in the success case.
*/
- duk_dup(ctx, idx);
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
+ duk_dup(thr, idx);
+ (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
+ if (!duk_is_string(thr, -1)) {
/* Error: try coercing error to string once. */
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
+ (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
+ if (!duk_is_string(thr, -1)) {
/* Double error */
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
+ duk_pop_unsafe(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR);
} else {
;
}
@@ -19384,50 +20055,49 @@ DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, du
/* String; may be a symbol, accepted. */
;
}
- DUK_ASSERT(duk_is_string(ctx, -1));
+ DUK_ASSERT(duk_is_string(thr, -1));
- duk_replace(ctx, idx);
- DUK_ASSERT(duk_get_string(ctx, idx) != NULL);
- return duk_get_lstring(ctx, idx, out_len);
+ duk_replace(thr, idx);
+ DUK_ASSERT(duk_get_string(thr, idx) != NULL);
+ return duk_get_lstring(thr, idx, out_len);
}
-DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- duk_to_primitive(ctx, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */
- h = duk_get_hstring(ctx, idx);
+ duk_to_primitive(thr, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */
+ h = duk_get_hstring(thr, idx);
if (h == NULL) {
/* The "is string?" check may seem unnecessary, but as things
* are duk_to_hstring() invokes ToString() which fails for
* symbols. But since symbols are already strings for Duktape
* C API, we check for that before doing the coercion.
*/
- h = duk_to_hstring(ctx, idx);
+ h = duk_to_hstring(thr, idx);
}
DUK_ASSERT(h != NULL);
return h;
}
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
-DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t idx) {
- (void) duk_safe_to_string(ctx, idx);
- DUK_ASSERT(duk_is_string(ctx, idx));
- DUK_ASSERT(duk_get_hstring(ctx, idx) != NULL);
- return duk_known_hstring(ctx, idx);
+DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_safe_to_string(thr, idx);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
+ return duk_known_hstring(thr, idx);
}
#endif
/* Push Object.prototype.toString() output for 'tv'. */
-DUK_INTERNAL void duk_push_class_string_tval(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
+DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) {
duk_small_uint_t stridx;
duk_hstring *h_strclass;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */
@@ -19499,21 +20169,20 @@ DUK_INTERNAL void duk_push_class_string_tval(duk_context *ctx, duk_tval *tv) {
h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx);
DUK_ASSERT(h_strclass != NULL);
- duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
+ duk_push_sprintf(thr, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
}
/* XXX: other variants like uint, u32 etc */
-DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
duk_tval *tv;
duk_tval tv_tmp;
duk_double_t d, dmin, dmax;
duk_int_t res;
duk_bool_t clamped = 0;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
@@ -19535,7 +20204,7 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, d
/* 'd' and 'res' agree here */
/* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
- tv = duk_get_tval(ctx, idx);
+ tv = duk_get_tval(thr, idx);
DUK_ASSERT(tv != NULL); /* not popped by side effect */
DUK_TVAL_SET_TVAL(&tv_tmp, tv);
#if defined(DUK_USE_FASTINT)
@@ -19566,40 +20235,42 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, d
return res;
}
-DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) {
+DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) {
duk_bool_t dummy;
- return duk_to_int_clamped_raw(ctx, idx, minval, maxval, &dummy);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ return duk_to_int_clamped_raw(thr, idx, minval, maxval, &dummy);
}
-DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) {
- return duk_to_int_clamped_raw(ctx, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
+DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_int_clamped_raw(thr, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
}
-DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
- tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNDEFINED: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_UNDEFINED);
break;
}
case DUK_TAG_NULL: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
break;
}
case DUK_TAG_BOOLEAN: {
if (DUK_TVAL_GET_BOOLEAN(tv)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_TRUE);
} else {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_FALSE);
}
break;
}
@@ -19614,7 +20285,7 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t idx) {
h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
+ DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
} else {
goto skip_replace;
}
@@ -19630,27 +20301,27 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t idx) {
* Symbol objects: duk_to_primitive() results in a plain symbol
* value, and duk_to_string() then causes a TypeError.
*/
- duk_to_primitive(ctx, idx, DUK_HINT_STRING);
- DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* ToPrimitive() must guarantee */
- DUK_ASSERT(!duk_is_object(ctx, idx));
- return duk_to_string(ctx, idx); /* Note: recursive call */
+ duk_to_primitive(thr, idx, DUK_HINT_STRING);
+ DUK_ASSERT(!duk_is_buffer(thr, idx)); /* ToPrimitive() must guarantee */
+ DUK_ASSERT(!duk_is_object(thr, idx));
+ return duk_to_string(thr, idx); /* Note: recursive call */
}
case DUK_TAG_POINTER: {
void *ptr = DUK_TVAL_GET_POINTER(tv);
if (ptr != NULL) {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr);
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) ptr);
} else {
/* Represent a null pointer as 'null' to be consistent with
* the JX format variant. Native '%p' format for a NULL
* pointer may be e.g. '(nil)'.
*/
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
}
break;
}
case DUK_TAG_LIGHTFUNC: {
/* Should match Function.prototype.toString() */
- duk_push_lightfunc_tostring(ctx, tv);
+ duk_push_lightfunc_tostring(thr, tv);
break;
}
#if defined(DUK_USE_FASTINT)
@@ -19660,8 +20331,8 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t idx) {
/* number */
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- duk_push_tval(ctx, tv);
- duk_numconv_stringify(ctx,
+ duk_push_tval(thr, tv);
+ duk_numconv_stringify(thr,
10 /*radix*/,
0 /*precision:shortest*/,
0 /*force_exponential*/);
@@ -19669,34 +20340,39 @@ DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t idx) {
}
}
- duk_replace(ctx, idx);
+ duk_replace(thr, idx);
skip_replace:
- DUK_ASSERT(duk_is_string(ctx, idx));
- return duk_require_string(ctx, idx);
+ DUK_ASSERT(duk_is_string(thr, idx));
+ return duk_require_string(thr, idx);
}
-DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *ret;
- DUK_ASSERT_CTX_VALID(ctx);
- duk_to_string(ctx, idx);
- ret = duk_get_hstring(ctx, idx);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_string(thr, idx);
+ ret = duk_get_hstring(thr, idx);
DUK_ASSERT(ret != NULL);
return ret;
}
-DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_context *ctx) {
- return duk_to_hstring(ctx, -1);
+DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_to_hstring(thr, -1);
}
-DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *ret;
- DUK_ASSERT_CTX_VALID(ctx);
- ret = duk_get_hstring(ctx, idx);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ret = duk_get_hstring(thr, idx);
if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) {
return ret;
}
- return duk_to_hstring(ctx, idx);
+ return duk_to_hstring(thr, idx);
}
/* Convert a plain buffer or any buffer object into a string, using the buffer
@@ -19706,34 +20382,34 @@ DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_context *ctx, duk_idx_
* string with the same bytes as in the buffer but rather (usually)
* '[object ArrayBuffer]'.
*/
-DUK_EXTERNAL const char *duk_buffer_to_string(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL const char *duk_buffer_to_string(duk_hthread *thr, duk_idx_t idx) {
void *ptr_src;
duk_size_t len;
const char *res;
- idx = duk_require_normalize_index(ctx, idx);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ idx = duk_require_normalize_index(thr, idx);
- ptr_src = duk_require_buffer_data(ctx, idx, &len);
+ ptr_src = duk_require_buffer_data(thr, idx, &len);
DUK_ASSERT(ptr_src != NULL || len == 0);
- res = duk_push_lstring(ctx, (const char *) ptr_src, len);
- duk_replace(ctx, idx);
+ res = duk_push_lstring(thr, (const char *) ptr_src, len);
+ duk_replace(thr, idx);
return res;
}
-DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) {
duk_hbuffer *h_buf;
const duk_uint8_t *src_data;
duk_size_t src_size;
duk_uint8_t *dst_data;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
- h_buf = duk_get_hbuffer(ctx, idx);
+ h_buf = duk_get_hbuffer(thr, idx);
if (h_buf != NULL) {
/* Buffer is kept as is, with the fixed/dynamic nature of the
* buffer only changed if requested. An external buffer
@@ -19762,10 +20438,10 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t
* explicitly requested). Symbols are rejected with a TypeError.
* XXX: C API could maybe allow symbol-to-buffer coercion?
*/
- src_data = (const duk_uint8_t *) duk_to_lstring(ctx, idx, &src_size);
+ src_data = (const duk_uint8_t *) duk_to_lstring(thr, idx, &src_size);
}
- dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
+ dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
if (DUK_LIKELY(src_size > 0)) {
/* When src_size == 0, src_data may be NULL (if source
* buffer is dynamic), and dst_data may be NULL (if
@@ -19774,7 +20450,7 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t
*/
DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
}
- duk_replace(ctx, idx);
+ duk_replace(thr, idx);
skip_copy:
if (out_size) {
@@ -19783,14 +20459,14 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t
return dst_data;
}
-DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL void *duk_to_pointer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
void *res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
- tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -19828,12 +20504,12 @@ DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx) {
break;
}
- duk_push_pointer(ctx, res);
- duk_replace(ctx, idx);
+ duk_push_pointer(thr, res);
+ duk_replace(thr, idx);
return res;
}
-DUK_LOCAL void duk__push_func_from_lightfunc(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags) {
+DUK_LOCAL void duk__push_func_from_lightfunc(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
duk_idx_t nargs;
duk_uint_t flags = 0; /* shared flags for a subset of types */
duk_small_uint_t lf_len;
@@ -19846,44 +20522,40 @@ DUK_LOCAL void duk__push_func_from_lightfunc(duk_context *ctx, duk_c_function fu
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
- /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
if ((duk_idx_t) lf_len != nargs) {
/* Explicit length is only needed if it differs from 'nargs'. */
- duk_push_int(ctx, (duk_int_t) lf_len);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_int(thr, (duk_int_t) lf_len);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
}
#if defined(DUK_USE_FUNC_NAME_PROPERTY)
- duk_push_lightfunc_name_raw(ctx, func, lf_flags);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
#endif
- nf = duk_known_hnatfunc(ctx, -1);
+ nf = duk_known_hnatfunc(thr, -1);
nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
-
- /* Enable DUKFUNC exotic behavior once properties are set up. */
- DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf);
}
-DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_uint_t flags = 0; /* shared flags for a subset of types */
duk_small_int_t proto = 0;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx);
- tv = DUK_GET_TVAL_POSIDX(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -19962,7 +20634,7 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t idx) {
duk_c_function func;
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
- duk__push_func_from_lightfunc(ctx, func, lf_flags);
+ duk__push_func_from_lightfunc(thr, func, lf_flags);
goto replace_value;
}
#if defined(DUK_USE_FASTINT)
@@ -19978,11 +20650,11 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t idx) {
goto create_object;
}
}
- DUK_ASSERT(duk_is_object(ctx, idx));
+ DUK_ASSERT(duk_is_object(thr, idx));
return;
create_object:
- (void) duk_push_object_helper(ctx, flags, proto);
+ (void) duk_push_object_helper(thr, flags, proto);
/* Note: Boolean prototype's internal value property is not writable,
* but duk_xdef_prop_stridx() disregards the write protection. Boolean
@@ -19991,19 +20663,21 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t idx) {
* String and buffer special behaviors are already enabled which is not
* ideal, but a write to the internal value is not affected by them.
*/
- duk_dup(ctx, idx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup(thr, idx);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
replace_value:
- duk_replace(ctx, idx);
- DUK_ASSERT(duk_is_object(ctx, idx));
+ duk_replace(thr, idx);
+ DUK_ASSERT(duk_is_object(thr, idx));
}
-DUK_INTERNAL duk_hobject *duk_to_hobject(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *ret;
- DUK_ASSERT_CTX_VALID(ctx);
- duk_to_object(ctx, idx);
- ret = duk_known_hobject(ctx, idx);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_to_object(thr, idx);
+ ret = duk_known_hobject(thr, idx);
return ret;
}
@@ -20011,20 +20685,20 @@ DUK_INTERNAL duk_hobject *duk_to_hobject(duk_context *ctx, duk_idx_t idx) {
* Type checking
*/
-DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t idx, duk_small_uint_t tag) {
+DUK_LOCAL duk_bool_t duk__tag_check(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t tag) {
duk_tval *tv;
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
return (DUK_TVAL_GET_TAG(tv) == tag);
}
-DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t idx, duk_uint_t flag_mask) {
+DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_hthread *thr, duk_idx_t idx, duk_uint_t flag_mask) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, idx);
+ obj = duk_get_hobject(thr, idx);
if (obj) {
return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
}
@@ -20070,19 +20744,19 @@ DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) {
#endif /* DUK_USE_PACKED_TVAL */
}
-DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_int_t duk_get_type(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
return duk_get_type_tval(tv);
}
#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_LOCAL const char *duk__type_names[] = {
+DUK_LOCAL const char * const duk__type_names[] = {
"none",
"undefined",
"null",
@@ -20095,22 +20769,26 @@ DUK_LOCAL const char *duk__type_names[] = {
"lightfunc"
};
-DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx) {
duk_int_t type_tag;
- type_tag = duk_get_type(ctx, idx);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ type_tag = duk_get_type(thr, idx);
DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
return duk__type_names[type_tag];
}
-#endif
+#endif /* DUK_USE_VERBOSE_ERRORS && DUK_USE_PARANOID_ERRORS */
-DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_context *ctx, duk_idx_t idx) {
+DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hobject *obj;
- tv = duk_get_tval_or_unused(ctx, idx);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -20130,10 +20808,10 @@ DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_context *ctx, duk_idx_t i
}
}
-DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t idx, duk_int_t type) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_check_type(duk_hthread *thr, duk_idx_t idx, duk_int_t type) {
+ DUK_ASSERT_API_ENTRY(thr);
- return (duk_get_type(ctx, idx) == type) ? 1 : 0;
+ return (duk_get_type(thr, idx) == type) ? 1 : 0;
}
DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) {
@@ -20171,27 +20849,25 @@ DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) {
#else /* DUK_USE_PACKED_TVAL */
DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
- return (duk_int_t) duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
+ return duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
#endif /* DUK_USE_PACKED_TVAL */
}
-DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
return duk_get_type_mask_tval(tv);
}
-DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t mask) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t mask) {
+ DUK_ASSERT_API_ENTRY(thr);
- if (DUK_LIKELY(duk_get_type_mask(ctx, idx) & mask)) {
+ if (DUK_LIKELY((duk_get_type_mask(thr, idx) & mask) != 0U)) {
return 1;
}
if (mask & DUK_TYPE_MASK_THROW) {
@@ -20201,25 +20877,25 @@ DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_UNDEFINED);
+DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_UNDEFINED);
}
-DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_NULL);
+DUK_EXTERNAL duk_bool_t duk_is_null(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_NULL);
}
-DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_BOOLEAN);
+DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_BOOLEAN);
}
-DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/*
* Number is special because it doesn't have a specific
@@ -20228,12 +20904,12 @@ DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx) {
/* XXX: shorter version for unpacked representation? */
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
return DUK_TVAL_IS_NUMBER(tv);
}
-DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_nan(duk_hthread *thr, duk_idx_t idx) {
/* XXX: This will now return false for non-numbers, even though they would
* coerce to NaN (as a general rule). In particular, duk_get_number()
* returns a NaN for non-numbers, so should this function also return
@@ -20242,45 +20918,45 @@ DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
/* XXX: for packed duk_tval an explicit "is number" check is unnecessary */
if (!DUK_TVAL_IS_NUMBER(tv)) {
return 0;
}
- return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
+ return (duk_bool_t) DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
}
-DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_STRING);
+DUK_EXTERNAL duk_bool_t duk_is_string(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_STRING);
}
-DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk_get_hstring_notsymbol(ctx, idx) != NULL;
+DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_get_hstring_notsymbol(thr, idx) != NULL;
}
-DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_OBJECT);
+DUK_EXTERNAL duk_bool_t duk_is_object(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_OBJECT);
}
-DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_BUFFER);
+DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_BUFFER);
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
return 1;
@@ -20294,29 +20970,29 @@ DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
return 0;
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
- return duk_is_buffer(ctx, idx);
+ return duk_is_buffer(thr, idx);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_POINTER);
+DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_POINTER);
}
-DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, idx, DUK_TAG_LIGHTFUNC);
+DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__tag_check(thr, idx, DUK_TAG_LIGHTFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- DUK_ASSERT_CTX_VALID(ctx);
- h = duk_get_hstring(ctx, idx);
+ DUK_ASSERT_API_ENTRY(thr);
+ h = duk_get_hstring(thr, idx);
/* Use DUK_LIKELY() here because caller may be more likely to type
* check an expected symbol than not.
*/
@@ -20326,73 +21002,110 @@ DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx) {
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_array(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, idx);
+ obj = duk_get_hobject(thr, idx);
if (obj) {
return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
}
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_function(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
+ }
if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
return 1;
}
- return duk__obj_flag_any_default_false(ctx,
- idx,
- DUK_HOBJECT_FLAG_COMPFUNC |
- DUK_HOBJECT_FLAG_NATFUNC |
- DUK_HOBJECT_FLAG_BOUNDFUNC);
+ return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
+DUK_INTERNAL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_UNREF(thr);
+
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ return 1;
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_constructable(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_get_tval_or_unused(thr, idx);
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ duk_hobject *h;
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ return DUK_HOBJECT_HAS_CONSTRUCTABLE(h) ? 1 : 0;
+ }
+ if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ return 1;
+ }
+ return 0;
+}
+
+DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
idx,
DUK_HOBJECT_FLAG_NATFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
+DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
idx,
DUK_HOBJECT_FLAG_COMPFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
+DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__obj_flag_any_default_false(thr,
idx,
DUK_HOBJECT_FLAG_BOUNDFUNC);
}
-DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_thread(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *obj;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- obj = duk_get_hobject(ctx, idx);
+ obj = duk_get_hobject(thr, idx);
if (obj) {
return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0);
}
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
@@ -20402,12 +21115,12 @@ DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) {
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
@@ -20417,12 +21130,12 @@ DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx) {
return 0;
}
-DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx) {
+DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv = duk_get_tval_or_unused(ctx, idx);
+ tv = duk_get_tval_or_unused(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
@@ -20432,20 +21145,22 @@ DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx)
return 0;
}
-DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_hthread *thr, duk_idx_t idx) {
duk_hobject *h;
duk_uint_t sanity;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_get_hobject(ctx, idx);
+ h = duk_get_hobject(thr, idx);
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
do {
if (!h) {
return DUK_ERR_NONE;
}
+
+ /* XXX: something more convenient? */
+
if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
return DUK_ERR_EVAL_ERROR;
}
@@ -20478,24 +21193,21 @@ DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx) {
* Pushers
*/
-DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
+DUK_INTERNAL void duk_push_tval(duk_hthread *thr, duk_tval *tv) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(tv != NULL);
- thr = (duk_hthread *) ctx;
+
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_TVAL(tv_slot, tv);
DUK_TVAL_INCREF(thr, tv); /* no side effects */
}
-DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
DUK__CHECK_SPACE();
/* Because value stack init policy is 'undefined above top',
@@ -20505,60 +21217,50 @@ DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
}
-DUK_EXTERNAL void duk_push_null(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_null(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_NULL(tv_slot);
}
-DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val) {
duk_tval *tv_slot;
duk_small_int_t b;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN(tv_slot, b);
}
-DUK_EXTERNAL void duk_push_true(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_true(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
}
-DUK_EXTERNAL void duk_push_false(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_false(duk_hthread *thr) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
}
/* normalize NaN which may not match our canonical internal NaN */
-DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_number(duk_hthread *thr, duk_double_t val) {
duk_tval *tv_slot;
duk_double_union du;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
du.d = val;
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
@@ -20566,13 +21268,11 @@ DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
DUK_TVAL_SET_NUMBER(tv_slot, du.d);
}
-DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
+DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val) {
#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
#if DUK_INT_MAX <= 0x7fffffffL
@@ -20586,12 +21286,10 @@ DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
}
#endif
#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
duk_tval *tv_slot;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
d = (duk_double_t) val;
tv_slot = thr->valstack_top++;
@@ -20599,13 +21297,11 @@ DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
#endif /* DUK_USE_FASTINT */
}
-DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
+DUK_EXTERNAL void duk_push_uint(duk_hthread *thr, duk_uint_t val) {
#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
#if DUK_UINT_MAX <= 0xffffffffUL
@@ -20620,12 +21316,10 @@ DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
}
#endif
#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
duk_tval *tv_slot;
duk_double_t d;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
d = (duk_double_t) val;
tv_slot = thr->valstack_top++;
@@ -20633,13 +21327,11 @@ DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
#endif /* DUK_USE_FASTINT */
}
-DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_nan(duk_hthread *thr) {
duk_tval *tv_slot;
duk_double_union du;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
DUK_DBLUNION_SET_NAN(&du);
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
@@ -20647,12 +21339,11 @@ DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
DUK_TVAL_SET_NUMBER(tv_slot, du.d);
}
-DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len) {
duk_hstring *h;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* check stack before interning (avoid hanging temp) */
DUK__CHECK_SPACE();
@@ -20681,52 +21372,47 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk
return (const char *) DUK_HSTRING_GET_DATA(h);
}
-DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) {
+ DUK_ASSERT_API_ENTRY(thr);
if (str) {
- return duk_push_lstring(ctx, str, DUK_STRLEN(str));
+ return duk_push_lstring(thr, str, DUK_STRLEN(str));
} else {
- duk_push_null(ctx);
+ duk_push_null(thr);
return NULL;
}
}
-DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
tv_slot = thr->valstack_top++;
DUK_TVAL_SET_POINTER(tv_slot, val);
}
-DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_context *ctx, duk_uint_t i) {
+DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i) {
duk_hstring *h_tmp;
+ DUK_ASSERT_API_ENTRY(thr);
+
/* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */
- duk_push_uint(ctx, (duk_uint_t) i);
- h_tmp = duk_to_hstring_m1(ctx);
+ duk_push_uint(thr, (duk_uint_t) i);
+ h_tmp = duk_to_hstring_m1(thr);
DUK_ASSERT(h_tmp != NULL);
return h_tmp;
}
-DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) {
- duk_hthread *thr;
+DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_object_coercible) {
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
DUK__CHECK_SPACE();
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
tv_slot = thr->valstack_top++;
- if (DUK_UNLIKELY(thr->callstack_top == 0)) {
+ if (DUK_UNLIKELY(thr->callstack_curr == NULL)) {
if (check_object_coercible) {
goto type_error;
}
@@ -20752,132 +21438,119 @@ DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_ob
DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
}
-DUK_EXTERNAL void duk_push_this(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_push_this(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 0 /*check_object_coercible*/);
+ duk__push_this_helper(thr, 0 /*check_object_coercible*/);
}
-DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL void duk_push_this_check_object_coercible(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
}
-DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
+DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- h = duk_to_hobject(ctx, -1);
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
+ h = duk_to_hobject(thr, -1);
DUK_ASSERT(h != NULL);
return h;
}
-DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- return duk_to_hstring_m1(ctx); /* This will reject all Symbol values; accepts Symbol objects. */
+ duk__push_this_helper(thr, 1 /*check_object_coercible*/);
+ return duk_to_hstring_m1(thr); /* This will reject all Symbol values; accepts Symbol objects. */
}
-DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
- DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr != NULL); /* caller required to know */
DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
return thr->valstack_bottom - 1;
}
-DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) {
duk_activation *act;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
+ DUK_ASSERT_API_ENTRY(thr);
act = thr->callstack_curr;
if (act != NULL) {
- duk_push_tval(ctx, &act->tv_func);
+ duk_push_tval(thr, &act->tv_func);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+DUK_EXTERNAL void duk_push_current_thread(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
if (thr->heap->curr_thread) {
- duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
+ duk_push_hobject(thr, (duk_hobject *) thr->heap->curr_thread);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
}
-DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
+ duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
}
/* XXX: size optimize */
-DUK_LOCAL void duk__push_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE)) {
+DUK_LOCAL void duk__push_stash(duk_hthread *thr) {
+ if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE)) {
DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
- duk_pop(ctx);
- duk_push_bare_object(ctx);
- duk_dup_top(ctx);
- duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
+ duk_pop_unsafe(thr);
+ duk_push_bare_object(thr);
+ duk_dup_top(thr);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
}
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
}
-DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_push_heap_stash(duk_hthread *thr) {
duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap->heap_object != NULL);
- duk_push_hobject(ctx, heap->heap_object);
- duk__push_stash(ctx);
+ duk_push_hobject(thr, heap->heap_object);
+ duk__push_stash(thr);
}
-DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_push_global_object(ctx);
- duk__push_stash(ctx);
+DUK_EXTERNAL void duk_push_global_stash(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_push_global_object(thr);
+ duk__push_stash(thr);
}
-DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- if (DUK_UNLIKELY(target_ctx == NULL)) {
+DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ if (DUK_UNLIKELY(target_thr == NULL)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
return; /* not reached */
}
- duk_push_hobject(ctx, (duk_hobject *) target_ctx);
- duk__push_stash(ctx);
+ duk_push_hobject(thr, (duk_hobject *) target_thr);
+ duk__push_stash(thr);
}
/* XXX: duk_ssize_t would be useful here */
-DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
+DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_hthread *thr, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
duk_int_t len;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_UNREF(thr);
/* NUL terminator handling doesn't matter here */
len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
@@ -20890,8 +21563,7 @@ DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size
return -1;
}
-DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va_list ap) {
duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
duk_bool_t pushed_buf = 0;
@@ -20899,13 +21571,13 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
duk_int_t len; /* XXX: duk_ssize_t */
const char *res;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* special handling of fmt==NULL */
if (!fmt) {
duk_hstring *h_str;
- duk_push_hstring_empty(ctx);
- h_str = duk_known_hstring(ctx, -1);
+ duk_push_hstring_empty(thr);
+ h_str = duk_known_hstring(thr, -1);
return (const char *) DUK_HSTRING_GET_DATA(h_str);
}
@@ -20926,14 +21598,14 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
buf = stack_buf;
} else if (!pushed_buf) {
pushed_buf = 1;
- buf = duk_push_dynamic_buffer(ctx, sz);
+ buf = duk_push_dynamic_buffer(thr, sz);
} else {
- buf = duk_resize_buffer(ctx, -1, sz);
+ buf = duk_resize_buffer(thr, -1, sz);
}
DUK_ASSERT(buf != NULL);
DUK_VA_COPY(ap_copy, ap);
- len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy);
+ len = duk__try_push_vsprintf(thr, buf, sz, fmt, ap_copy);
va_end(ap_copy);
if (len >= 0) {
break;
@@ -20949,33 +21621,32 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va
/* Cannot use duk_buffer_to_string() on the buffer because it is
* usually larger than 'len'; 'buf' is also usually a stack buffer.
*/
- res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
+ res = duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
if (pushed_buf) {
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
}
return res;
}
-DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL const char *duk_push_sprintf(duk_hthread *thr, const char *fmt, ...) {
va_list ap;
const char *ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* allow fmt==NULL */
va_start(ap, fmt);
- ret = duk_push_vsprintf(ctx, fmt, ap);
+ ret = duk_push_vsprintf(thr, fmt, ap);
va_end(ap);
return ret;
}
-DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
duk_tval *tv_slot;
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(prototype_bidx == -1 ||
(prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
@@ -20994,7 +21665,7 @@ DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t ho
/* object is now reachable */
if (prototype_bidx >= 0) {
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, thr->builtins[prototype_bidx]);
} else {
DUK_ASSERT(prototype_bidx == -1);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
@@ -21003,38 +21674,35 @@ DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t ho
return h;
}
-DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
duk_hobject *h;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
+ h = duk_push_object_helper(thr, hobject_flags_and_class, -1);
DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, proto);
return h;
}
-DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
- (void) duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
DUK_BIDX_OBJECT_PROTOTYPE);
- return duk_get_top_index_unsafe(ctx);
+ return duk_get_top_index_unsafe(thr);
}
-DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr) {
duk_uint_t flags;
duk_harray *obj;
duk_idx_t ret;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
@@ -21045,8 +21713,7 @@ DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
obj = duk_harray_alloc(thr, flags);
DUK_ASSERT(obj != NULL);
- /* XXX: since prototype is NULL, could save a check */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]);
tv_slot = thr->valstack_top;
DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
@@ -21058,13 +21725,13 @@ DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
return ret;
}
-DUK_INTERNAL duk_harray *duk_push_harray(duk_context *ctx) {
+DUK_INTERNAL duk_harray *duk_push_harray(duk_hthread *thr) {
/* XXX: API call could do this directly, cast to void in API macro. */
- duk_hthread *thr;
duk_harray *a;
- thr = (duk_hthread *) ctx;
- (void) duk_push_array(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_push_array(thr);
DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1));
a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1);
DUK_ASSERT(a != NULL);
@@ -21074,12 +21741,14 @@ DUK_INTERNAL duk_harray *duk_push_harray(duk_context *ctx) {
/* Push a duk_harray with preallocated size (.length also set to match size).
* Caller may then populate array part of the duk_harray directly.
*/
-DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_context *ctx, duk_uint32_t size) {
+DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size) {
duk_harray *a;
- a = duk_push_harray(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ a = duk_push_harray(thr);
- duk_hobject_realloc_props((duk_hthread *) ctx,
+ duk_hobject_realloc_props(thr,
(duk_hobject *) a,
0,
size,
@@ -21089,13 +21758,22 @@ DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_context *ctx, duk_uint32_
return a;
}
-DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size) {
+ duk_harray *a;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ a = duk_push_harray_with_size(thr, size);
+ DUK_ASSERT(a != NULL);
+ return DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
+}
+
+DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) {
duk_hthread *obj;
duk_idx_t ret;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
@@ -21134,11 +21812,10 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
duk_hthread_copy_builtin_objects(thr, obj);
}
- /* default prototype (Note: 'obj' must be reachable) */
- /* XXX: since prototype is NULL, could save a check */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
+ /* default prototype */
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
- /* Initial stack size satisfies the stack spare constraints so there
+ /* Initial stack size satisfies the stack slack constraints so there
* is no need to require stack here.
*/
DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
@@ -21147,12 +21824,11 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
return ret;
}
-DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) {
duk_hcompfunc *obj;
duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
@@ -21163,6 +21839,7 @@ DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx) {
obj = duk_hcompfunc_alloc(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
DUK_HOBJECT_FLAG_COMPFUNC |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
if (DUK_UNLIKELY(obj == NULL)) {
@@ -21176,19 +21853,49 @@ DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx) {
DUK_HOBJECT_INCREF(thr, obj);
thr->valstack_top++;
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+ /* default prototype */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
return obj;
}
-DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) {
+ duk_hboundfunc *obj;
+ duk_tval *tv_slot;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK__CHECK_SPACE();
+ obj = duk_hboundfunc_alloc(thr->heap,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_BOUNDFUNC |
+ DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
+ if (!obj) {
+ DUK_ERROR_ALLOC_FAILED(thr);
+ }
+
+ tv_slot = thr->valstack_top++;
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
+ DUK_HOBJECT_INCREF(thr, obj);
+
+ /* Prototype is left as NULL because the caller always sets it (and
+ * it depends on the target function).
+ */
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
+
+ return obj;
+}
+
+DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx) {
duk_hnatfunc *obj;
duk_idx_t ret;
duk_tval *tv_slot;
duk_int16_t func_nargs;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK__CHECK_SPACE();
@@ -21218,9 +21925,8 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
thr->valstack_top++;
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
-
+ DUK_ASSERT_BIDX_VALID(proto_bidx);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[proto_bidx]);
return ret;
api_error:
@@ -21228,31 +21934,35 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
return 0; /* not reached */
}
-DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- return duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Default prototype is a Duktape specific %NativeFunctionPrototype%
+ * which provides .length and .name getters.
+ */
+ return duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
}
-DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_INTERNAL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
@@ -21260,15 +21970,17 @@ DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Must use Function.prototype for standard built-in functions. */
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
}
-DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
+DUK_INTERNAL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
duk_uint_t flags;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_CALLABLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_FLAG_NATFUNC |
DUK_HOBJECT_FLAG_NEWENV |
@@ -21276,15 +21988,15 @@ DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
+ /* Must use Function.prototype for standard built-in functions. */
+ (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
}
-DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval tv_tmp;
+DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
duk_small_uint_t lf_flags;
+ duk_tval *tv_slot;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
@@ -21302,11 +22014,12 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun
goto api_error;
}
- lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs);
- DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags);
- duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */
- DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
- return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
+ lf_flags = DUK_LFUNC_FLAGS_PACK((duk_small_int_t) magic, (duk_small_uint_t) length, (duk_small_uint_t) nargs);
+ tv_slot = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_slot));
+ DUK_TVAL_SET_LIGHTFUNC(tv_slot, func, lf_flags);
+ DUK_ASSERT(tv_slot >= thr->valstack_bottom);
+ return (duk_idx_t) (tv_slot - thr->valstack_bottom);
api_error:
DUK_ERROR_TYPE_INVALID_ARGS(thr);
@@ -21314,12 +22027,11 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function fun
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
duk_hbufobj *obj;
duk_tval *tv_slot;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(prototype_bidx >= 0);
DUK__CHECK_SPACE();
@@ -21327,7 +22039,7 @@ DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_context *ctx, duk_uint_t hobje
obj = duk_hbufobj_alloc(thr, hobject_flags_and_class);
DUK_ASSERT(obj != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
DUK_ASSERT_HBUFOBJ_VALID(obj);
tv_slot = thr->valstack_top;
@@ -21364,23 +22076,20 @@ static const duk_uint32_t duk__bufobj_flags_lookup[] = {
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
- duk_hthread *thr;
+DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
+ duk_hobject *h_arraybuf;
duk_uint32_t tmp;
duk_uint_t classnum;
duk_uint_t protobidx;
duk_uint_t lookupidx;
duk_uint_t uint_offset, uint_length, uint_added;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_API_ENTRY(thr);
/* The underlying types for offset/length in duk_hbufobj is
- * duk_uint_t; make sure argument values fit and that
- * offset + length does not wrap.
+ * duk_uint_t; make sure argument values fit.
*/
uint_offset = (duk_uint_t) byte_offset;
uint_length = (duk_uint_t) byte_length;
@@ -21389,11 +22098,6 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer,
goto range_error;
}
}
- uint_added = uint_offset + uint_length;
- if (DUK_UNLIKELY(uint_added < uint_offset)) {
- goto range_error;
- }
- DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
lookupidx = flags;
@@ -21404,18 +22108,56 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer,
classnum = tmp >> 24;
protobidx = (tmp >> 16) & 0xff;
- h_val = duk_require_hbuffer(ctx, idx_buffer);
+ h_arraybuf = duk_get_hobject(thr, idx_buffer);
+ if (h_arraybuf != NULL && /* argument is an object */
+ flags != DUK_BUFOBJ_ARRAYBUFFER && /* creating a view */
+ DUK_HOBJECT_GET_CLASS_NUMBER(h_arraybuf) == DUK_HOBJECT_CLASS_ARRAYBUFFER /* argument is ArrayBuffer */) {
+ duk_uint_t tmp_offset;
+
+ DUK_ASSERT_HBUFOBJ_VALID((duk_hbufobj *) h_arraybuf);
+ h_val = ((duk_hbufobj *) h_arraybuf)->buf;
+ if (DUK_UNLIKELY(h_val == NULL)) {
+ goto arg_error;
+ }
+
+ tmp_offset = uint_offset + ((duk_hbufobj *) h_arraybuf)->offset;
+ if (DUK_UNLIKELY(tmp_offset < uint_offset)) {
+ goto range_error;
+ }
+ uint_offset = tmp_offset;
+
+ /* Note intentional difference to new TypedArray(): we allow
+ * caller to create an uncovered typed array (which is memory
+ * safe); new TypedArray() rejects it.
+ */
+ } else {
+ /* Handle unexpected object arguments here too, for nice error
+ * messages.
+ */
+ h_arraybuf = NULL;
+ h_val = duk_require_hbuffer(thr, idx_buffer);
+ }
+
+ /* Wrap check for offset+length. */
+ uint_added = uint_offset + uint_length;
+ if (DUK_UNLIKELY(uint_added < uint_offset)) {
+ goto range_error;
+ }
+ DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
+
DUK_ASSERT(h_val != NULL);
- h_bufobj = duk_push_bufobj_raw(ctx,
+ h_bufobj = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
- protobidx);
+ (duk_small_int_t) protobidx);
DUK_ASSERT(h_bufobj != NULL);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
+ h_bufobj->buf_prop = h_arraybuf;
+ DUK_HOBJECT_INCREF_ALLOWNULL(thr, h_arraybuf);
h_bufobj->offset = uint_offset;
h_bufobj->length = uint_length;
h_bufobj->shift = (tmp >> 4) & 0x0f;
@@ -21427,7 +22169,7 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer,
* provided as .buffer property of the view. The ArrayBuffer is
* referenced via duk_hbufobj->buf_prop and an inherited .buffer
* accessor returns it. The ArrayBuffer is created lazily on first
- * access so we don't need to do anything more here.
+ * access if necessary so we don't need to do anything more here.
*/
return;
@@ -21440,36 +22182,39 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer,
return; /* not reached */
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
+DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx_buffer);
DUK_UNREF(byte_offset);
DUK_UNREF(byte_length);
DUK_UNREF(flags);
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
duk_hobject *proto;
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
- duk_bool_t noblame_fileline;
+ duk_small_uint_t augment_flags;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
DUK_UNREF(filename);
DUK_UNREF(line);
/* Error code also packs a tracedata related flag. */
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
- noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
+ augment_flags = 0;
+ if (err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE) {
+ augment_flags = DUK_AUGMENT_FLAG_NOBLAME_FILELINE;
+ }
#endif
err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
/* error gets its 'name' from the prototype */
proto = duk_error_prototype_from_code(thr, err_code);
- (void) duk_push_object_helper_proto(ctx,
+ (void) duk_push_object_helper_proto(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
@@ -21477,8 +22222,8 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcod
/* ... and its 'message' from an instance property */
if (fmt) {
- duk_push_vsprintf(ctx, fmt, ap);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_vsprintf(thr, fmt, ap);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
} else {
/* If no explicit message given, put error code into message field
* (as a number). This is not fully in keeping with the Ecmascript
@@ -21486,8 +22231,8 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcod
* constructors use ToString() on their argument). However, it's
* probably more useful than having a separate 'code' property.
*/
- duk_push_int(ctx, err_code);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_int(thr, err_code);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
}
/* XXX: .code = err_code disabled, not sure if useful */
@@ -21495,49 +22240,48 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcod
/* Creation time error augmentation */
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
/* filename may be NULL in which case file/line is not recorded */
- duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */
+ duk_err_augment_error_create(thr, thr, filename, line, augment_flags); /* may throw an error */
#endif
- return duk_get_top_index_unsafe(ctx);
+ return duk_get_top_index_unsafe(thr);
}
-DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
+DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
va_list ap;
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
return ret;
}
#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
+DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
const char *filename = duk_api_global_filename;
duk_int_t line = duk_api_global_line;
va_list ap;
duk_idx_t ret;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
duk_api_global_filename = NULL;
duk_api_global_line = 0;
va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
return ret;
}
#endif /* DUK_USE_VARIADIC_MACROS */
-DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_small_uint_t flags) {
duk_tval *tv_slot;
duk_hbuffer *h;
void *buf_data;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK__CHECK_SPACE();
@@ -21559,13 +22303,17 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_sm
return (void *) buf_data;
}
-DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_context *ctx, duk_size_t len) {
- return duk_push_buffer_raw(ctx, len, DUK_BUF_FLAG_NOZERO);
+DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_push_buffer_raw(thr, len, DUK_BUF_FLAG_NOZERO);
}
-DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_context *ctx, duk_size_t len) {
+DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) {
void *ptr;
- ptr = duk_push_buffer_raw(ctx, len, 0);
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ ptr = duk_push_buffer_raw(thr, len, 0);
#if !defined(DUK_USE_ZERO_BUFFER_DATA)
/* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
* is not set.
@@ -21575,14 +22323,113 @@ DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_context *ctx, duk_size_t len)
return ptr;
}
+#if defined(DUK_USE_ES6_PROXY)
+DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
+ duk_hobject *h_target;
+ duk_hobject *h_handler;
+ duk_hproxy *h_proxy;
+ duk_tval *tv_slot;
+ duk_uint_t flags;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(proxy_flags);
+
+ /* DUK__CHECK_SPACE() unnecessary because the Proxy is written to
+ * value stack in-place.
+ */
+#if 0
+ DUK__CHECK_SPACE();
+#endif
+
+ /* Reject a proxy object as the target because it would need
+ * special handling in property lookups. (ES2015 has no such
+ * restriction.)
+ */
+ h_target = duk_require_hobject_promote_mask(thr, -2, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ DUK_ASSERT(h_target != NULL);
+ if (DUK_HOBJECT_IS_PROXY(h_target)) {
+ goto fail_args;
+ }
+
+ /* Reject a proxy object as the handler because it would cause
+ * potentially unbounded recursion. (ES2015 has no such
+ * restriction.)
+ *
+ * There's little practical reason to use a lightfunc or a plain
+ * buffer as the handler table: one could only provide traps via
+ * their prototype objects (Function.prototype and ArrayBuffer.prototype).
+ * Even so, as lightfuncs and plain buffers mimic their object
+ * counterparts, they're promoted and accepted here.
+ */
+ h_handler = duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ DUK_ASSERT(h_handler != NULL);
+ if (DUK_HOBJECT_IS_PROXY(h_handler)) {
+ goto fail_args;
+ }
+
+ /* XXX: Proxy object currently has no prototype, so ToPrimitive()
+ * coercion fails which is a bit confusing.
+ */
+
+ /* CALLABLE and CONSTRUCTABLE flags are copied from the (initial)
+ * target, see ES2015 Sections 9.5.15 and 9.5.13.
+ */
+ flags = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h_target) &
+ (DUK_HOBJECT_FLAG_CALLABLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE);
+ flags |= DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ;
+ if (flags & DUK_HOBJECT_FLAG_CALLABLE) {
+ flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION) |
+ DUK_HOBJECT_FLAG_SPECIAL_CALL;
+ } else {
+ flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT);
+ }
+
+ h_proxy = duk_hproxy_alloc(thr, flags);
+ DUK_ASSERT(h_proxy != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_proxy) == NULL);
+
+ /* Initialize Proxy target and handler references; avoid INCREF
+ * by stealing the value stack refcounts via direct value stack
+ * manipulation. INCREF is needed for the Proxy itself however.
+ */
+ DUK_ASSERT(h_target != NULL);
+ h_proxy->target = h_target;
+ DUK_ASSERT(h_handler != NULL);
+ h_proxy->handler = h_handler;
+ DUK_ASSERT_HPROXY_VALID(h_proxy);
+
+ DUK_ASSERT(duk_get_hobject(thr, -2) == h_target);
+ DUK_ASSERT(duk_get_hobject(thr, -1) == h_handler);
+ tv_slot = thr->valstack_top - 2;
+ DUK_ASSERT(tv_slot >= thr->valstack_bottom);
+ DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) h_proxy);
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_proxy);
+ tv_slot++;
+ DUK_TVAL_SET_UNDEFINED(tv_slot); /* [ ... target handler ] -> [ ... proxy undefined ] */
+ thr->valstack_top = tv_slot; /* -> [ ... proxy ] */
+
+ DUK_DD(DUK_DDPRINT("created Proxy: %!iT", duk_get_tval(thr, -1)));
+
+ return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom - 1);
+
+ fail_args:
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+}
+#else /* DUK_USE_ES6_PROXY */
+DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(proxy_flags);
+ DUK_ERROR_UNSUPPORTED(thr);
+}
+#endif /* DUK_USE_ES6_PROXY */
+
#if defined(DUK_USE_ASSERTIONS)
-DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) {
+DUK_LOCAL void duk__validate_push_heapptr(duk_hthread *thr, void *ptr) {
duk_heaphdr *h;
duk_heaphdr *curr;
- duk_hthread *thr;
duk_bool_t found = 0;
- thr = (duk_hthread *) ctx;
h = (duk_heaphdr *) ptr;
if (h == NULL) {
/* Allowed. */
@@ -21675,12 +22522,11 @@ DUK_LOCAL void duk__validate_push_heapptr(duk_context *ctx, void *ptr) {
}
#endif /* DUK_USE_ASSERTIONS */
-DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_hthread *thr, void *ptr) {
duk_idx_t ret;
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Reviving an object using a heap pointer is a dangerous API
* operation: if the application doesn't guarantee that the
@@ -21690,7 +22536,7 @@ DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
*/
#if defined(DUK_USE_ASSERTIONS)
- duk__validate_push_heapptr(ctx, ptr);
+ duk__validate_push_heapptr(thr, ptr);
#endif
DUK__CHECK_SPACE();
@@ -21768,83 +22614,79 @@ DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
}
/* Push object with no prototype, i.e. a "bare" object. */
-DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_context *ctx) {
- (void) duk_push_object_helper(ctx,
+DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
-1); /* no prototype */
- return duk_get_top_index_unsafe(ctx);
+ return duk_get_top_index_unsafe(thr);
}
-DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
+DUK_INTERNAL void duk_push_hstring(duk_hthread *thr, duk_hstring *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_STRING(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_uint_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+DUK_INTERNAL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT_STRIDX_VALID(stridx);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
}
-DUK_INTERNAL void duk_push_hstring_empty(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING));
+DUK_INTERNAL void duk_push_hstring_empty(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING));
}
-DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
+DUK_INTERNAL void duk_push_hobject(duk_hthread *thr, duk_hobject *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_OBJECT(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
+DUK_INTERNAL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
+
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(h != NULL);
+
DUK_TVAL_SET_BUFFER(&tv, h);
- duk_push_tval(ctx, &tv);
+ duk_push_tval(thr, &tv);
}
-DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
+DUK_INTERNAL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
+
+ duk_push_hobject(thr, thr->builtins[builtin_idx]);
}
/*
* Poppers
*/
-DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_n_unsafe_raw(duk_hthread *thr, duk_idx_t count) {
duk_tval *tv;
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_tval *tv_end;
#endif
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
-
- if (DUK_UNLIKELY(count < 0)) {
- DUK_ERROR_RANGE_INVALID_COUNT(thr);
- return;
- }
-
- if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
- DUK_ERROR_RANGE_INVALID_COUNT(thr);
- }
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
#if defined(DUK_USE_REFERENCE_COUNTING)
tv = thr->valstack_top;
@@ -21870,49 +22712,37 @@ DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
-DUK_INTERNAL void duk_pop_n_unsafe(duk_context *ctx, duk_idx_t count) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-#if defined(DUK_USE_REFERENCE_COUNTING)
- duk_tval *tv_end;
-#endif
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(count >= 0);
+DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
-#if defined(DUK_USE_REFERENCE_COUNTING)
- tv = thr->valstack_top;
- tv_end = tv - count;
- while (tv != tv_end) {
- tv--;
- DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
- }
- thr->valstack_top = tv;
- DUK_REFZERO_CHECK_FAST(thr);
-#else
- tv = thr->valstack_top;
- while (count > 0) {
- count--;
- tv--;
- DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED(tv);
+ if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ return;
}
- thr->valstack_top = tv;
-#endif
+ DUK_ASSERT(count >= 0);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ duk__pop_n_unsafe_raw(thr, count);
+}
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, count);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_n_unsafe_raw(thr, count);
}
+#endif /* DUK_USE_PREFER_SIZE */
-/* Pop N elements without DECREF (in effect "stealing" the refcounts). */
+/* Pop N elements without DECREF (in effect "stealing" any actual refcounts). */
#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(count >= 0);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
@@ -21929,8 +22759,9 @@ DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) {
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
#else /* DUK_USE_REFERENCE_COUNTING */
-DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) {
- duk_pop_n_unsafe(ctx, count);
+DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, count);
}
#endif /* DUK_USE_REFERENCE_COUNTING */
@@ -21938,51 +22769,116 @@ DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_context *ctx, duk_idx_t count) {
* compile a specialized function for it.
*/
#if defined(DUK_USE_PREFER_SIZE)
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 1);
+DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 1);
}
-#else
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 1);
+}
+DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 1);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_unsafe_raw(duk_hthread *thr) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
- DUK_ERROR_RANGE_INVALID_COUNT(thr);
- }
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
- tv = --thr->valstack_top; /* tv points to element just below prev top */
+ tv = --thr->valstack_top;
DUK_ASSERT(tv >= thr->valstack_bottom);
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
#else
DUK_TVAL_SET_UNDEFINED(tv);
#endif
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ }
+
+ duk__pop_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+ DUK_TVAL_SET_UNDEFINED(tv);
+
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
#endif /* !DUK_USE_PREFER_SIZE */
-/* Unsafe internal variant which assumes there are enough values on the value
- * stack so that a top check can be skipped safely.
- */
#if defined(DUK_USE_PREFER_SIZE)
-DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n_unsafe(ctx, 1);
+DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_nodecref_unsafe(thr);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
+ thr->valstack_top--;
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
+#endif /* !DUK_USE_PREFER_SIZE */
+
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 2);
+}
+DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 2);
+}
+DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 2);
}
#else
-DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_2_unsafe_raw(duk_hthread *thr) {
duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
- tv = --thr->valstack_top; /* tv points to element just below prev top */
+ tv = --thr->valstack_top;
+ DUK_ASSERT(tv >= thr->valstack_bottom);
+#if defined(DUK_USE_REFERENCE_COUNTING)
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
+#else
+ DUK_TVAL_SET_UNDEFINED(tv);
+#endif
+ tv = --thr->valstack_top;
DUK_ASSERT(tv >= thr->valstack_bottom);
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
@@ -21992,16 +22888,47 @@ DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) {
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
}
+DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) {
+ DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ }
+
+ duk__pop_2_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk__pop_2_unsafe_raw(thr);
+}
+DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
+
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 2));
+ thr->valstack_top -= 2;
+
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+}
#endif /* !DUK_USE_PREFER_SIZE */
-DUK_EXTERNAL void duk_pop_2(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 2);
+DUK_EXTERNAL void duk_pop_3(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n(thr, 3);
+}
+
+DUK_INTERNAL void duk_pop_3_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_unsafe(thr, 3);
}
-DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 3);
+DUK_INTERNAL void duk_pop_3_nodecref_unsafe(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_pop_n_nodecref_unsafe(thr, 3);
}
/*
@@ -22009,43 +22936,40 @@ DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
*/
/* XXX: pack index range? array index offset? */
-DUK_INTERNAL void duk_pack(duk_context *ctx, duk_idx_t count) {
- duk_hthread *thr;
- duk_harray *a;
+DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
duk_tval *tv_src;
duk_tval *tv_dst;
duk_tval *tv_curr;
duk_tval *tv_limit;
duk_idx_t top;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
- if (DUK_UNLIKELY(count < 0 || count > top)) {
+ DUK_ASSERT(top >= 0);
+ if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) {
+ /* Also handles negative count. */
DUK_ERROR_RANGE_INVALID_COUNT(thr);
return;
}
+ DUK_ASSERT(count >= 0);
/* Wrapping is controlled by the check above: value stack top can be
- * at most thr->valstack_max which is low enough so that multiplying
- * with sizeof(duk_tval) won't wrap.
+ * at most DUK_USE_VALSTACK_LIMIT which is low enough so that
+ * multiplying with sizeof(duk_tval) won't wrap.
*/
- DUK_ASSERT(count >= 0 && count <= (duk_idx_t) thr->valstack_max);
+ DUK_ASSERT(count >= 0 && count <= (duk_idx_t) DUK_USE_VALSTACK_LIMIT);
DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */
- a = duk_push_harray_with_size(ctx, (duk_uint32_t) count); /* XXX: uninitialized would be OK */
- DUK_ASSERT(a != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ASIZE((duk_hobject *) a) == (duk_uint32_t) count);
- DUK_ASSERT(count == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a) != NULL);
- DUK_ASSERT((duk_idx_t) a->length == count);
+ tv_dst = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); /* XXX: uninitialized would be OK */
+ DUK_ASSERT(count == 0 || tv_dst != NULL);
/* Copy value stack values directly to the array part without
* any refcount updates: net refcount changes are zero.
*/
tv_src = thr->valstack_top - count - 1;
- tv_dst = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
/* Overwrite result array to final value stack location and wipe
@@ -22067,26 +22991,118 @@ DUK_INTERNAL void duk_pack(duk_context *ctx, duk_idx_t count) {
thr->valstack_top = tv_dst + 1;
}
-#if 0
-/* XXX: unpack to position? */
-DUK_INTERNAL void duk_unpack(duk_context *ctx) {
- /* - dense with length <= a_part
- * - dense with length > a_part
- * - sparse
- * - array-like but not actually an array?
- * - how to deal with 'unused' values (gaps); inherit or ignore?
- */
+DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, idx);
+ if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv))) {
+ duk_hobject *h;
+ duk_uint32_t len;
+ duk_uint32_t i;
+
+ h = DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ DUK_UNREF(h);
+
+#if defined(DUK_USE_ARRAY_FASTPATH) /* close enough */
+ if (DUK_LIKELY(DUK_HOBJECT_IS_ARRAY(h) &&
+ ((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h))) {
+ duk_harray *h_arr;
+ duk_tval *tv_src;
+ duk_tval *tv_dst;
+
+ h_arr = (duk_harray *) h;
+ len = h_arr->length;
+ if (DUK_UNLIKELY(len >= 0x80000000UL)) {
+ goto fail_over_2g;
+ }
+ duk_require_stack(thr, (duk_idx_t) len);
+
+ /* The potential allocation in duk_require_stack() may
+ * run a finalizer which modifies the argArray so that
+ * e.g. becomes sparse. So, we need to recheck that the
+ * array didn't change size and that there's still a
+ * valid backing array part.
+ *
+ * XXX: alternatively, could prevent finalizers for the
+ * duration.
+ */
+ if (DUK_UNLIKELY(len != h_arr->length ||
+ h_arr->length > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr))) {
+ goto skip_fast;
+ }
+
+ /* Main fast path: arguments array is almost always
+ * an actual array (though it might also be an arguments
+ * object).
+ */
+
+ DUK_DDD(DUK_DDDPRINT("fast path for %ld elements", (long) h_arr->length));
+ tv_src = DUK_HOBJECT_A_GET_BASE(thr->heap, h);
+ tv_dst = thr->valstack_top;
+ while (len-- > 0) {
+ DUK_ASSERT(tv_dst < thr->valstack_end);
+ if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_src))) {
+ /* Gaps are very unlikely. Skip over them,
+ * without an ancestor lookup (technically
+ * not compliant).
+ */
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_dst)); /* valstack policy */
+ } else {
+ DUK_TVAL_SET_TVAL(tv_dst, tv_src);
+ DUK_TVAL_INCREF(thr, tv_dst);
+ }
+ tv_src++;
+ tv_dst++;
+ }
+ DUK_ASSERT(tv_dst <= thr->valstack_end);
+ thr->valstack_top = tv_dst;
+ return (duk_idx_t) h_arr->length;
+ }
+ skip_fast:
+#endif /* DUK_USE_ARRAY_FASTPATH */
+
+ /* Slow path: actual lookups. The initial 'length' lookup
+ * decides the output length, regardless of side effects that
+ * may resize or change the argArray while we read the
+ * indices.
+ */
+ idx = duk_normalize_index(thr, idx);
+ duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
+ len = duk_to_uint32(thr, -1); /* ToUint32() coercion required */
+ if (DUK_UNLIKELY(len >= 0x80000000UL)) {
+ goto fail_over_2g;
+ }
+ duk_pop_unsafe(thr);
+ DUK_DDD(DUK_DDDPRINT("slow path for %ld elements", (long) len));
+
+ duk_require_stack(thr, (duk_idx_t) len);
+ for (i = 0; i < len; i++) {
+ duk_get_prop_index(thr, idx, (duk_uarridx_t) i);
+ }
+ return (duk_idx_t) len;
+ } else if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) {
+ return 0;
+ }
+
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ return 0;
+
+ fail_over_2g:
+ DUK_ERROR_RANGE_INVALID_LENGTH(thr);
+ return 0;
}
-#endif
/*
* Error throwing
*/
-DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) {
duk_tval *tv_val;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
@@ -22107,12 +23123,12 @@ DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) {
duk_hthread_sync_and_null_currpc(thr);
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
duk_err_augment_error_throw(thr);
#endif
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
- tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
duk_err_check_debugger_integration(thr);
@@ -22127,10 +23143,8 @@ DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) {
DUK_UNREACHABLE();
}
-DUK_EXTERNAL void duk_fatal_raw(duk_context *ctx, const char *err_msg) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_fatal_raw(duk_hthread *thr, const char *err_msg) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(thr->heap->fatal_func != NULL);
@@ -22153,72 +23167,80 @@ DUK_EXTERNAL void duk_fatal_raw(duk_context *ctx, const char *err_msg) {
}
}
-DUK_EXTERNAL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- (void) duk_throw(ctx);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
+ (void) duk_throw(thr);
}
-DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
+DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
va_list ap;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
va_start(ap, fmt);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
- (void) duk_throw(ctx);
+ (void) duk_throw(thr);
}
#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, va_list ap));
+DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap));
-DUK_LOCAL void duk__throw_error_from_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, va_list ap) {
+DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap) {
const char *filename;
duk_int_t line;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
filename = duk_api_global_filename;
line = duk_api_global_line;
duk_api_global_filename = NULL;
duk_api_global_line = 0;
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- (void) duk_throw(ctx);
+ duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
+ (void) duk_throw(thr);
}
#define DUK__ERROR_STASH_SHARED(code) do { \
va_list ap; \
va_start(ap, fmt); \
- duk__throw_error_from_stash(ctx, (code), fmt, ap); \
+ duk__throw_error_from_stash(thr, (code), fmt, ap); \
va_end(ap); \
/* Never reached; if return 0 here, gcc/clang will complain. */ \
} while (0)
-DUK_EXTERNAL duk_ret_t duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(err_code);
}
-DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR);
}
-DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR);
}
-DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR);
}
-DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR);
}
-DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR);
}
-DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR);
}
-DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ...) {
+DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_hthread *thr, const char *fmt, ...) {
+ DUK_ASSERT_API_ENTRY(thr);
DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR);
}
#endif /* DUK_USE_VARIADIC_MACROS */
@@ -22227,14 +23249,13 @@ DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ..
* Comparison
*/
-DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_bool_t duk_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_get_tval(ctx, idx1);
- tv2 = duk_get_tval(ctx, idx2);
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
if ((tv1 == NULL) || (tv2 == NULL)) {
return 0;
}
@@ -22245,13 +23266,13 @@ DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t i
return duk_js_equals(thr, tv1, tv2);
}
-DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
+DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_get_tval(ctx, idx1);
- tv2 = duk_get_tval(ctx, idx2);
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
if ((tv1 == NULL) || (tv2 == NULL)) {
return 0;
}
@@ -22260,13 +23281,13 @@ DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_
return duk_js_strict_equals(tv1, tv2);
}
-DUK_EXTERNAL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
+DUK_EXTERNAL duk_bool_t duk_samevalue(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- tv1 = duk_get_tval(ctx, idx1);
- tv2 = duk_get_tval(ctx, idx2);
+ tv1 = duk_get_tval(thr, idx1);
+ tv2 = duk_get_tval(thr, idx2);
if ((tv1 == NULL) || (tv2 == NULL)) {
return 0;
}
@@ -22279,10 +23300,10 @@ DUK_EXTERNAL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_
* instanceof
*/
-DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
+DUK_EXTERNAL duk_bool_t duk_instanceof(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
duk_tval *tv1, *tv2;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* Index validation is strict, which differs from duk_equals().
* The strict behavior mimics how instanceof itself works, e.g.
@@ -22290,19 +23311,19 @@ DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx
* be somewhat inconsistent if rval would be allowed to be
* non-existent without a TypeError.
*/
- tv1 = duk_require_tval(ctx, idx1);
+ tv1 = duk_require_tval(thr, idx1);
DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, idx2);
+ tv2 = duk_require_tval(thr, idx2);
DUK_ASSERT(tv2 != NULL);
- return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2);
+ return duk_js_instanceof(thr, tv1, tv2);
}
/*
* Lightfunc
*/
-DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags) {
+DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
/* Lightfunc name, includes Duktape/C native function pointer, which
* can often be used to locate the function from a symbol table.
* The name also includes the 16-bit duk_tval flags field because it
@@ -22315,32 +23336,37 @@ DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_context *ctx, duk_c_function f
* is accessed).
*/
- duk_push_sprintf(ctx, "light_");
- duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func));
- duk_push_sprintf(ctx, "_%04x", (unsigned int) lf_flags);
- duk_concat(ctx, 3);
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk_push_sprintf(thr, "light_");
+ duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
+ duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags);
+ duk_concat(thr, 3);
}
-DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
+DUK_INTERNAL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv) {
duk_c_function func;
duk_small_uint_t lf_flags;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
+
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
- duk_push_lightfunc_name_raw(ctx, func, lf_flags);
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
}
-DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
+DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) {
duk_c_function func;
duk_small_uint_t lf_flags;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
- DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */
- duk_push_string(ctx, "function ");
- duk_push_lightfunc_name_raw(ctx, func, lf_flags);
- duk_push_string(ctx, "() { [lightfunc code] }");
- duk_concat(ctx, 3);
+ DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */
+ duk_push_string(thr, "function ");
+ duk_push_lightfunc_name_raw(thr, func, lf_flags);
+ duk_push_string(thr, "() { [lightfunc code] }");
+ duk_concat(thr, 3);
}
/*
@@ -22350,12 +23376,13 @@ DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
* bytes from memory.
*/
-DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) {
+DUK_INTERNAL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz) {
duk_uint8_t buf[32 * 2];
duk_uint8_t *p, *q;
duk_small_uint_t i;
duk_small_uint_t t;
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
p = buf;
@@ -22374,7 +23401,7 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du
*p++ = duk_lc_digits[t & 0x0f];
}
- duk_push_lstring(ctx, (const char *) buf, sz * 2);
+ duk_push_lstring(thr, (const char *) buf, sz * 2);
}
/*
@@ -22384,25 +23411,27 @@ DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, du
* and is not intended to be fast (but small and safe).
*/
-#define DUK__READABLE_STRING_MAXCHARS 32
+/* String limits for summary strings. */
+#define DUK__READABLE_SUMMARY_MAXCHARS 96 /* maximum supported by helper */
+#define DUK__READABLE_STRING_MAXCHARS 32 /* for strings/symbols */
+#define DUK__READABLE_ERRMSG_MAXCHARS 96 /* for error messages */
/* 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;
+DUK_LOCAL void duk__push_hstring_readable_unicode(duk_hthread *thr, duk_hstring *h_input, duk_small_uint_t maxchars) {
const duk_uint8_t *p, *p_start, *p_end;
- duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
+ duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_SUMMARY_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_CTX_VALID(thr);
DUK_ASSERT(h_input != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(maxchars <= DUK__READABLE_SUMMARY_MAXCHARS);
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
@@ -22415,7 +23444,7 @@ DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring
if (p >= p_end) {
break;
}
- if (nchars == DUK__READABLE_STRING_MAXCHARS) {
+ if (nchars == maxchars) {
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
*q++ = (duk_uint8_t) DUK_ASC_PERIOD;
@@ -22440,24 +23469,32 @@ DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring
}
*q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) (q - buf));
}
-DUK_LOCAL const char *duk__push_string_tval_readable(duk_context *ctx, duk_tval *tv, duk_bool_t error_aware) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval *tv, duk_bool_t error_aware) {
+ DUK_ASSERT_CTX_VALID(thr);
/* 'tv' may be NULL */
if (tv == NULL) {
- duk_push_string(ctx, "none");
+ duk_push_string(thr, "none");
} else {
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_STRING: {
- /* XXX: symbol support (maybe in summary rework branch) */
- duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
+ duk_hstring *h = DUK_TVAL_GET_STRING(tv);
+ if (DUK_HSTRING_HAS_SYMBOL(h)) {
+ /* XXX: string summary produces question marks
+ * so this is not very ideal.
+ */
+ duk_push_string(thr, "[Symbol ");
+ duk_push_string(thr, duk__get_symbol_type_string(h));
+ duk_push_string(thr, " ");
+ duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
+ duk_push_string(thr, "]");
+ duk_concat(thr, 5);
+ break;
+ }
+ duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
break;
}
case DUK_TAG_OBJECT: {
@@ -22475,16 +23512,15 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_context *ctx, duk_tval
*/
duk_tval *tv_msg;
tv_msg = duk_hobject_find_existing_entry_tval_ptr(thr->heap, h, DUK_HTHREAD_STRING_MESSAGE(thr));
- if (tv_msg) {
- /* It's important this summarization is
- * not error aware to avoid unlimited
- * recursion when the .message property
- * is e.g. another error.
+ if (tv_msg != NULL && DUK_TVAL_IS_STRING(tv_msg)) {
+ /* It's critical to avoid recursion so
+ * only summarize a string .message.
*/
- return duk_push_string_tval_readable(ctx, tv_msg);
+ duk__push_hstring_readable_unicode(thr, DUK_TVAL_GET_STRING(tv_msg), DUK__READABLE_ERRMSG_MAXCHARS);
+ break;
}
}
- duk_push_class_string_tval(ctx, tv);
+ duk_push_class_string_tval(thr, tv);
break;
}
case DUK_TAG_BUFFER: {
@@ -22495,49 +23531,51 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_context *ctx, duk_tval
/* 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));
+ duk_push_sprintf(thr, "[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_m2(ctx);
+ duk_push_tval(thr, tv);
+ duk_push_sprintf(thr, "(%s)", duk_to_string(thr, -1));
+ duk_remove_m2(thr);
break;
}
default: {
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
break;
}
}
}
- return duk_to_string(ctx, -1);
+ return duk_to_string(thr, -1);
}
-DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__push_string_tval_readable(ctx, tv, 0 /*error_aware*/);
+DUK_INTERNAL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__push_string_tval_readable(thr, tv, 0 /*error_aware*/);
}
-DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t idx) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, idx));
+DUK_INTERNAL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk_push_string_tval_readable(thr, duk_get_tval(thr, idx));
}
-DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_context *ctx, duk_tval *tv) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__push_string_tval_readable(ctx, tv, 1 /*error_aware*/);
+DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv) {
+ DUK_ASSERT_API_ENTRY(thr);
+ return duk__push_string_tval_readable(thr, tv, 1 /*error_aware*/);
}
-DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_context *ctx, duk_hstring *h) {
+DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h) {
const duk_uint8_t *p;
const duk_uint8_t *p_end;
const duk_uint8_t *q;
+ DUK_ASSERT_API_ENTRY(thr);
+
/* .toString() */
- duk_push_string(ctx, "Symbol(");
+ duk_push_string(thr, "Symbol(");
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
p_end = p + DUK_HSTRING_GET_BYTELEN(h);
DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80);
@@ -22552,24 +23590,67 @@ DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_context *ctx, duk_hstri
break;
}
}
- duk_push_lstring(ctx, (const char *) p, (duk_size_t) (q - p));
- duk_push_string(ctx, ")");
- duk_concat(ctx, 3);
+ duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p));
+ duk_push_string(thr, ")");
+ duk_concat(thr, 3);
+}
+
+/*
+ * Functions
+ */
+
+#if 0 /* not used yet */
+DUK_INTERNAL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h) {
+ duk_c_function func;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h));
+
+ duk_push_sprintf(thr, "native_");
+ func = h->func;
+ duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
+ duk_push_sprintf(thr, "_%04x_%04x",
+ (unsigned int) (duk_uint16_t) h->nargs,
+ (unsigned int) (duk_uint16_t) h->magic);
+ duk_concat(thr, 3);
+}
+#endif
+
+/*
+ * duk_tval slice copy
+ */
+
+DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count) {
+ duk_tval *tv;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
+ DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */
+ DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
+
+ tv = tv_dst;
+ while (count-- > 0) {
+ DUK_TVAL_INCREF(thr, tv);
+ tv++;
+ }
}
/* automatic undefs */
+#undef DUK__ASSERT_SPACE
#undef DUK__CHECK_SPACE
#undef DUK__ERROR_STASH_SHARED
#undef DUK__PACK_ARGS
+#undef DUK__READABLE_ERRMSG_MAXCHARS
#undef DUK__READABLE_STRING_MAXCHARS
+#undef DUK__READABLE_SUMMARY_MAXCHARS
/*
* String manipulation
*/
/* #include duk_internal.h -> already included */
-DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) {
duk_uint_t count;
duk_uint_t i;
duk_size_t idx;
@@ -22577,7 +23658,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
duk_hstring *h;
duk_uint8_t *buf;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
if (DUK_UNLIKELY(count_in <= 0)) {
if (count_in < 0) {
@@ -22585,14 +23666,14 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
return;
}
DUK_ASSERT(count_in == 0);
- duk_push_hstring_empty(ctx);
+ duk_push_hstring_empty(thr);
return;
}
count = (duk_uint_t) count_in;
if (is_join) {
duk_size_t t1, t2, limit;
- h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1);
+ h = duk_to_hstring(thr, -((duk_idx_t) count) - 1);
DUK_ASSERT(h != NULL);
/* A bit tricky overflow test, see doc/code-issues.rst. */
@@ -22610,7 +23691,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
for (i = count; i >= 1; i--) {
duk_size_t new_len;
- h = duk_to_hstring(ctx, -((duk_idx_t) i));
+ h = duk_to_hstring(thr, -((duk_idx_t) i));
new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
/* Impose a string maximum length, need to handle overflow
@@ -22629,7 +23710,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
/* Use stack allocated buffer to ensure reachability in errors
* (e.g. intern error).
*/
- buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
DUK_ASSERT(buf != NULL);
/* [ ... (sep) str1 str2 ... strN buf ] */
@@ -22637,11 +23718,11 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
idx = 0;
for (i = count; i >= 1; i--) {
if (is_join && i != count) {
- h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
+ h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
- h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
+ h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
@@ -22653,16 +23734,16 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
/* Get rid of the strings early to minimize memory use before intern. */
if (is_join) {
- duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */
- duk_pop_n(ctx, count);
+ duk_replace(thr, -((duk_idx_t) count) - 2); /* overwrite sep */
+ duk_pop_n(thr, (duk_idx_t) count);
} else {
- duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */
- duk_pop_n(ctx, count-1);
+ duk_replace(thr, -((duk_idx_t) count) - 1); /* overwrite str1 */
+ duk_pop_n(thr, (duk_idx_t) (count - 1));
}
/* [ ... buf ] */
- (void) duk_buffer_to_string(ctx, -1); /* Safe if inputs are safe. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
/* [ ... res ] */
return;
@@ -22671,31 +23752,74 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in,
DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
}
-DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
+DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
- duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
+ duk__concat_and_join_helper(thr, count, 0 /*is_join*/);
}
-DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
+#if defined(DUK_USE_PREFER_SIZE)
+DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ duk_concat(thr, 2);
+}
+#else /* DUK_USE_PREFER_SIZE */
+DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
+ duk_hstring *h1;
+ duk_hstring *h2;
+ duk_uint8_t *buf;
+ duk_size_t len1;
+ duk_size_t len2;
+ duk_size_t len;
- duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(duk_get_top(thr) >= 2); /* Trusted caller. */
+
+ h1 = duk_to_hstring(thr, -2);
+ h2 = duk_to_hstring(thr, -1);
+ len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
+ len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
+ len = len1 + len2;
+ if (DUK_UNLIKELY(len < len1 || /* wrapped */
+ len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) {
+ goto error_overflow;
+ }
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
+ DUK_ASSERT(buf != NULL);
+
+ DUK_MEMCPY((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
+ DUK_MEMCPY((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
+
+ /* [ ... str1 str2 buf ] */
+
+ duk_replace(thr, -3);
+ duk_pop_unsafe(thr);
+ return;
+
+ error_overflow:
+ DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
+}
+#endif /* DUK_USE_PREFER_SIZE */
+
+DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) {
+ DUK_ASSERT_API_ENTRY(thr);
+
+ duk__concat_and_join_helper(thr, count, 1 /*is_join*/);
}
/* XXX: could map/decode be unified with duk_unicode_support.c code?
* Case conversion needs also the character surroundings though.
*/
-DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
duk_hstring *h_input;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- h_input = duk_require_hstring(ctx, idx); /* Accept symbols. */
+ h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
@@ -22711,19 +23835,18 @@ DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_
}
}
-DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) {
duk_hstring *h_input;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_normalize_index(ctx, idx);
+ idx = duk_normalize_index(thr, idx);
- h_input = duk_require_hstring(ctx, idx); /* Accept symbols. */
+ h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
@@ -22748,22 +23871,21 @@ DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_f
}
DUK_BW_COMPACT(thr, bw);
- (void) duk_buffer_to_string(ctx, -1); /* Safe, extended UTF-8 encoded. */
- duk_replace(ctx, idx);
+ (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 encoded. */
+ duk_replace(thr, idx);
}
-DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
duk_hstring *h;
duk_hstring *res;
duk_size_t start_byte_offset;
duk_size_t end_byte_offset;
duk_size_t charlen;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx); /* Accept symbols. */
- h = duk_require_hstring(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
+ h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
charlen = DUK_HSTRING_GET_CHARLEN(h);
@@ -22794,24 +23916,23 @@ DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t star
DUK_HSTRING_GET_DATA(h) + start_byte_offset,
(duk_uint32_t) (end_byte_offset - start_byte_offset));
- duk_push_hstring(ctx, res);
- duk_replace(ctx, idx);
+ duk_push_hstring(thr, res);
+ duk_replace(thr, idx);
}
/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
* forwards with a callback to process codepoints?
*/
-DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
duk_codepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
- idx = duk_require_normalize_index(ctx, idx); /* Accept symbols. */
- h = duk_require_hstring(ctx, idx);
+ idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
+ h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
p_start = DUK_HSTRING_GET_DATA(h);
@@ -22873,22 +23994,21 @@ DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t idx) {
return;
}
- duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start));
- duk_replace(ctx, idx);
+ duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start));
+ duk_replace(thr, idx);
}
-DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) {
duk_hstring *h;
duk_ucodepoint_t cp;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_API_ENTRY(thr);
/* XXX: Share code with String.prototype.charCodeAt? Main difference
* is handling of clamped offsets.
*/
- h = duk_require_hstring(ctx, idx); /* Accept symbols. */
+ h = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h != NULL);
DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */
@@ -22906,18 +24026,56 @@ DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, d
/* #include duk_internal.h -> already included */
-DUK_EXTERNAL duk_double_t duk_get_now(duk_context *ctx) {
- return ((duk_double_t) DUK_USE_DATE_GET_NOW((ctx)));
+DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
+ /* Ecmascript time, with millisecond fractions. Exposed via
+ * duk_get_now() for example.
+ */
+ DUK_UNREF(thr);
+ return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
+}
+
+DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) {
+ /* Ecmascript time without millisecond fractions. Exposed via
+ * the Date built-in which doesn't allow fractions.
+ */
+ DUK_UNREF(thr);
+ return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr));
+}
+
+DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) {
+ DUK_UNREF(thr);
+#if defined(DUK_USE_GET_MONOTONIC_TIME)
+ return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr);
+#else
+ return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
+#endif
}
-DUK_EXTERNAL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp) {
+DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
+
+ /* This API intentionally allows millisecond fractions. */
+ return duk_time_get_ecmascript_time(thr);
+}
+
+#if 0 /* XXX: worth exposing? */
+DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_UNREF(thr);
+
+ return duk_time_get_monotonic_time(thr);
+}
+#endif
+
+DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) {
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_uint_t flags;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(comp != NULL); /* XXX: or check? */
- DUK_UNREF(ctx);
+ DUK_UNREF(thr);
/* Convert as one-based, but change month to zero-based to match the
* Ecmascript Date built-in behavior 1:1.
@@ -22926,6 +24084,8 @@ DUK_EXTERNAL void duk_time_to_components(duk_context *ctx, duk_double_t timeval,
duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
+ /* XXX: sub-millisecond accuracy for the API */
+
DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0);
comp->year = dparts[DUK_DATE_IDX_YEAR];
comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0;
@@ -22937,14 +24097,14 @@ DUK_EXTERNAL void duk_time_to_components(duk_context *ctx, duk_double_t timeval,
comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY];
}
-DUK_EXTERNAL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp) {
+DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) {
duk_double_t d;
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_uint_t flags;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(comp != NULL); /* XXX: or check? */
- DUK_UNREF(ctx);
+ DUK_UNREF(thr);
/* Match Date constructor behavior (with UTC time). Month is given
* as zero-based. Day-of-month is given as one-based so normalize
@@ -23028,27 +24188,27 @@ DUK_EXTERNAL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_comp
* Note that length is left on stack (it could be popped, but that's not
* usually necessary because call handling will clean it up automatically).
*/
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) {
+DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_hthread *thr) {
duk_uint32_t len;
/* XXX: push more directly? */
- (void) duk_push_this_coercible_to_object(ctx);
- DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(ctx, -1));
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH);
- len = duk_to_uint32(ctx, -1);
+ (void) duk_push_this_coercible_to_object(thr);
+ DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(thr, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_LENGTH);
+ len = duk_to_uint32(thr, -1);
/* -> [ ... ToObject(this) ToUint32(length) ] */
return len;
}
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
+DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) {
/* Range limited to [0, 0x7fffffff] range, i.e. range that can be
* represented with duk_int32_t. Use this when the method doesn't
* handle the full 32-bit unsigned range correctly.
*/
- duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
+ duk_uint32_t ret = duk__push_this_obj_len_u32(thr);
if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
- DUK_ERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
+ DUK_ERROR_RANGE_INVALID_LENGTH(thr);
}
return ret;
}
@@ -23060,13 +24220,11 @@ DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
* significant fraction to improve performance. Return a non-NULL duk_harray
* pointer when all fast path criteria are met, NULL otherwise.
*/
-DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_context *ctx) {
- duk_hthread *thr;
+DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h;
duk_uint_t flags_mask, flags_bits, flags_value;
- thr = (duk_hthread *) ctx;
DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */
tv = DUK_GET_THIS_TVAL_PTR(thr);
@@ -23115,34 +24273,34 @@ DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_context *ctx) {
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_hthread *thr) {
duk_idx_t nargs;
duk_harray *a;
duk_double_t d;
duk_uint32_t len;
duk_uint32_t len_prealloc;
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
- if (nargs == 1 && duk_is_number(ctx, 0)) {
+ if (nargs == 1 && duk_is_number(thr, 0)) {
/* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
- d = duk_get_number(ctx, 0);
- len = duk_to_uint32(ctx, 0);
+ d = duk_get_number(thr, 0);
+ len = duk_to_uint32(thr, 0);
if (((duk_double_t) len) != d) {
- DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
/* For small lengths create a dense preallocated array.
* For large arrays preallocate an initial part.
*/
len_prealloc = len < 64 ? len : 64;
- a = duk_push_harray_with_size(ctx, len_prealloc);
+ a = duk_push_harray_with_size(thr, len_prealloc);
DUK_ASSERT(a != NULL);
a->length = len;
return 1;
}
- duk_pack(ctx, nargs);
+ duk_pack(thr, nargs);
return 1;
}
@@ -23150,11 +24308,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
* isArray()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_hthread *thr) {
duk_hobject *h;
- h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
- duk_push_boolean(ctx, (h != NULL));
+ h = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_ARRAY);
+ duk_push_boolean(thr, (h != NULL));
return 1;
}
@@ -23162,12 +24320,12 @@ DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
* toString()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_JOIN);
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) {
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_JOIN);
/* [ ... this func ] */
- if (!duk_is_callable(ctx, -1)) {
+ if (!duk_is_callable(thr, -1)) {
/* Fall back to the initial (original) Object.toString(). We don't
* currently have pointers to the built-in functions, only the top
* level global objects (like "Array") so this is now done in a bit
@@ -23179,20 +24337,20 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
* but should have no visible side effects.
*/
DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
- duk_set_top(ctx, 0);
- return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */
+ duk_set_top(thr, 0);
+ return duk_bi_object_prototype_to_string(thr); /* has access to 'this' binding */
}
/* [ ... this func ] */
- duk_insert(ctx, -2);
+ duk_insert(thr, -2);
/* [ ... func this ] */
DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call_method(ctx, 0);
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_call_method(thr, 0);
return 1;
}
@@ -23201,7 +24359,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
* concat()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) {
duk_idx_t i, n;
duk_uarridx_t idx, idx_last;
duk_uarridx_t j, len;
@@ -23212,10 +24370,10 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
* (as the element is dup()'d anyway).
*/
- (void) duk_push_this_coercible_to_object(ctx);
- duk_insert(ctx, 0);
- n = duk_get_top(ctx);
- duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_insert(thr, 0);
+ n = duk_get_top(thr);
+ duk_push_array(thr); /* -> [ ToObject(this) item1 ... itemN arr ] */
/* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
* (which differs from the official algorithm). If no error is thrown, this
@@ -23227,14 +24385,14 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
idx = 0;
idx_last = 0;
for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, n + 1);
+ DUK_ASSERT_TOP(thr, n + 1);
/* [ ToObject(this) item1 ... itemN arr ] */
- duk_dup(ctx, i);
- h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
+ duk_dup(thr, i);
+ h = duk_get_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_ARRAY);
if (!h) {
- duk_xdef_prop_index_wec(ctx, -2, idx++);
+ duk_xdef_prop_index_wec(thr, -2, idx++);
idx_last = idx;
continue;
}
@@ -23244,15 +24402,15 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
/* XXX: an array can have length higher than 32 bits; this is not handled
* correctly now.
*/
- len = (duk_uarridx_t) duk_get_length(ctx, -1);
+ len = (duk_uarridx_t) duk_get_length(thr, -1);
for (j = 0; j < len; j++) {
- if (duk_get_prop_index(ctx, -1, j)) {
+ if (duk_get_prop_index(thr, -1, j)) {
/* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
- duk_xdef_prop_index_wec(ctx, -3, idx++);
+ duk_xdef_prop_index_wec(thr, -3, idx++);
idx_last = idx;
} else {
idx++;
- duk_pop(ctx);
+ duk_pop_undefined(thr);
#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
/* According to E5.1 Section 15.4.4.4 nonexistent trailing
* elements do not affect 'length' of the result. Test262
@@ -23266,17 +24424,17 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
#endif
}
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
/* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
* in the end, but because we're operating with an internal value which
* is known to be an array, this should be equivalent.
*/
- duk_push_uarridx(ctx, idx_last);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_uarridx(thr, idx_last);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- DUK_ASSERT_TOP(ctx, n + 1);
+ DUK_ASSERT_TOP(thr, n + 1);
return 1;
}
@@ -23293,39 +24451,39 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
* There is no fancy handling; the prefix gets re-joined multiple times.
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_hthread *thr) {
duk_uint32_t len, count;
duk_uint32_t idx;
- duk_small_int_t to_locale_string = duk_get_current_magic(ctx);
+ duk_small_int_t to_locale_string = duk_get_current_magic(thr);
duk_idx_t valstack_required;
/* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
* setting the top essentially pushes an undefined to the stack,
* thus defaulting to a comma separator.
*/
- duk_set_top(ctx, 1);
- if (duk_is_undefined(ctx, 0)) {
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
+ duk_set_top(thr, 1);
+ if (duk_is_undefined(thr, 0)) {
+ duk_pop_undefined(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_COMMA);
} else {
- duk_to_string(ctx, 0);
+ duk_to_string(thr, 0);
}
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
/* [ sep ToObject(this) len ] */
DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1),
(unsigned long) len));
/* The extra (+4) is tight. */
- valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
- DUK__ARRAY_MID_JOIN_LIMIT : len) + 4;
- duk_require_stack(ctx, valstack_required);
+ valstack_required = (duk_idx_t) ((len >= DUK__ARRAY_MID_JOIN_LIMIT ?
+ DUK__ARRAY_MID_JOIN_LIMIT : len) + 4);
+ duk_require_stack(thr, valstack_required);
- duk_dup_0(ctx);
+ duk_dup_0(thr);
/* [ sep ToObject(this) len sep ] */
@@ -23338,9 +24496,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
/* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
(long) count, (long) idx, (long) len));
- duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
- duk_dup_0(ctx); /* -> [ sep ToObject(this) len str sep ] */
- duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */
+ duk_join(thr, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
+ duk_dup_0(thr); /* -> [ sep ToObject(this) len str sep ] */
+ duk_insert(thr, -2); /* -> [ sep ToObject(this) len sep str ] */
count = 1;
}
if (idx >= len) {
@@ -23348,18 +24506,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
break;
}
- duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx);
- if (duk_is_null_or_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_hstring_empty(ctx);
+ duk_get_prop_index(thr, 1, (duk_uarridx_t) idx);
+ if (duk_is_null_or_undefined(thr, -1)) {
+ duk_pop_nodecref_unsafe(thr);
+ duk_push_hstring_empty(thr);
} else {
if (to_locale_string) {
- duk_to_object(ctx, -1);
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
- duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */
- duk_call_method(ctx, 0);
+ duk_to_object(thr, -1);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_LOCALE_STRING);
+ duk_insert(thr, -2); /* -> [ ... toLocaleString ToObject(val) ] */
+ duk_call_method(thr, 0);
}
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
count++;
@@ -23376,14 +24534,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_ARRAY_FASTPATH)
-DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_context *ctx, duk_harray *h_arr) {
- duk_hthread *thr;
+DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_hthread *thr, duk_harray *h_arr) {
duk_tval *tv_arraypart;
duk_tval *tv_val;
duk_uint32_t len;
- thr = (duk_hthread *) ctx;
-
tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
len = h_arr->length;
if (len <= 0) {
@@ -23419,59 +24574,58 @@ DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_context *ctx, duk_harray *h_arr)
}
#endif /* DUK_USE_ARRAY_FASTPATH */
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t idx;
#if defined(DUK_USE_ARRAY_FASTPATH)
duk_harray *h_arr;
#endif
- DUK_ASSERT_TOP(ctx, 0);
+ DUK_ASSERT_TOP(thr, 0);
#if defined(DUK_USE_ARRAY_FASTPATH)
- h_arr = duk__arraypart_fastpath_this(ctx);
+ h_arr = duk__arraypart_fastpath_this(thr);
if (h_arr) {
- return duk__array_pop_fastpath(ctx, h_arr);
+ return duk__array_pop_fastpath(thr, h_arr);
}
#endif
/* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 0;
}
idx = len - 1;
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_push_u32(ctx, idx);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) idx);
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) idx);
+ duk_push_u32(thr, idx);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 1;
}
#if defined(DUK_USE_ARRAY_FASTPATH)
-DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_context *ctx, duk_harray *h_arr) {
- duk_hthread *thr;
+DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_hthread *thr, duk_harray *h_arr) {
duk_tval *tv_arraypart;
duk_tval *tv_src;
duk_tval *tv_dst;
duk_uint32_t len;
duk_idx_t i, n;
- thr = (duk_hthread *) ctx;
-
len = h_arr->length;
tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
- if (DUK_UNLIKELY(len + n < len)) {
+ DUK_ASSERT(n >= 0);
+ DUK_ASSERT((duk_uint32_t) n <= DUK_UINT32_MAX);
+ if (DUK_UNLIKELY(len + (duk_uint32_t) n < len)) {
DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */
}
- if (len + n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) {
+ if (len + (duk_uint32_t) n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) {
/* Array part would need to be extended. Rely on slow path
* for now.
*
@@ -23492,16 +24646,16 @@ DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_context *ctx, duk_harray *h_arr
tv_dst++;
}
thr->valstack_top = thr->valstack_bottom;
- len += n;
+ len += (duk_uint32_t) n;
h_arr->length = len;
DUK_ASSERT((duk_uint_t) len == len);
- duk_push_uint(ctx, (duk_uint_t) len);
+ duk_push_uint(thr, (duk_uint_t) len);
return 1;
}
#endif /* DUK_USE_ARRAY_FASTPATH */
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_hthread *thr) {
/* Note: 'this' is not necessarily an Array object. The push()
* algorithm is supposed to work for other kinds of objects too,
* so the algorithm has e.g. an explicit update for the 'length'
@@ -23515,10 +24669,10 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
#endif
#if defined(DUK_USE_ARRAY_FASTPATH)
- h_arr = duk__arraypart_fastpath_this(ctx);
+ h_arr = duk__arraypart_fastpath_this(thr);
if (h_arr) {
duk_ret_t rc;
- rc = duk__array_push_fastpath(ctx, h_arr);
+ rc = duk__array_push_fastpath(thr, h_arr);
if (rc != 0) {
return rc;
}
@@ -23526,8 +24680,8 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
}
#endif
- n = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
+ n = duk_get_top(thr);
+ len = duk__push_this_obj_len_u32(thr);
/* [ arg1 ... argN obj length ] */
@@ -23543,18 +24697,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
if (len + (duk_uint32_t) n < len) {
DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
- DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
for (i = 0; i < n; i++) {
- duk_dup(ctx, i);
- duk_put_prop_index(ctx, -3, len + i);
+ duk_dup(thr, i);
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) (len + (duk_uint32_t) i));
}
- len += n;
+ len += (duk_uint32_t) n;
- duk_push_u32(ctx, len);
- duk_dup_top(ctx);
- duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, len);
+ duk_dup_top(thr);
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
/* [ arg1 ... argN obj length new_length ] */
return 1;
@@ -23570,7 +24724,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
* may use a negative offset.
*/
-DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) {
+DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_hthread *thr, duk_int_t idx1, duk_int_t idx2) {
duk_bool_t have1, have2;
duk_bool_t undef1, undef2;
duk_small_int_t ret;
@@ -23599,12 +24753,12 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
return 0;
}
- have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1);
- have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2);
+ have1 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx1);
+ have2 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx2);
DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
(long) idx1, (long) idx2, (long) have1, (long) have2,
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
if (have1) {
if (have2) {
@@ -23623,8 +24777,8 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
}
}
- undef1 = duk_is_undefined(ctx, -2);
- undef2 = duk_is_undefined(ctx, -1);
+ undef1 = duk_is_undefined(thr, -2);
+ undef2 = duk_is_undefined(thr, -1);
if (undef1) {
if (undef2) {
ret = 0;
@@ -23642,20 +24796,20 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
}
}
- if (!duk_is_undefined(ctx, idx_fn)) {
+ if (!duk_is_undefined(thr, idx_fn)) {
duk_double_t d;
/* No need to check callable; duk_call() will do that. */
- duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */
- duk_insert(ctx, -3); /* -> [ ... fn x y ] */
- duk_call(ctx, 2); /* -> [ ... res ] */
+ duk_dup(thr, idx_fn); /* -> [ ... x y fn ] */
+ duk_insert(thr, -3); /* -> [ ... fn x y ] */
+ duk_call(thr, 2); /* -> [ ... res ] */
/* ES5 is a bit vague about what to do if the return value is
* not a number. ES2015 provides a concrete description:
* http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare.
*/
- d = duk_to_number_m1(ctx);
+ d = duk_to_number_m1(thr);
if (d < 0.0) {
ret = -1;
} else if (d > 0.0) {
@@ -23667,7 +24821,7 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
ret = 0;
}
- duk_pop(ctx);
+ duk_pop_nodecref_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
return ret;
}
@@ -23675,8 +24829,8 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
/* string compare is the default (a bit oddly) */
/* XXX: any special handling for plain array; causes repeated coercion now? */
- h1 = duk_to_hstring(ctx, -2);
- h2 = duk_to_hstring_m1(ctx);
+ h1 = duk_to_hstring(thr, -2);
+ h2 = duk_to_hstring_m1(thr);
DUK_ASSERT(h1 != NULL);
DUK_ASSERT(h2 != NULL);
@@ -23684,12 +24838,12 @@ DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t id
goto pop_ret;
pop_ret:
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
return ret;
}
-DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) {
+DUK_LOCAL void duk__array_sort_swap(duk_hthread *thr, duk_int_t l, duk_int_t r) {
duk_bool_t have_l, have_r;
duk_idx_t idx_obj = 1; /* fixed offset in valstack */
@@ -23698,32 +24852,32 @@ DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r)
}
/* swap elements; deal with non-existent elements correctly */
- have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
+ have_l = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) l);
+ have_r = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) r);
if (have_r) {
/* right exists, [[Put]] regardless whether or not left exists */
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
+ duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) l);
} else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- duk_pop(ctx);
+ duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) l);
+ duk_pop_undefined(thr);
}
if (have_l) {
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
+ duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) r);
} else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
- duk_pop(ctx);
+ duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) r);
+ duk_pop_undefined(thr);
}
}
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
/* Debug print which visualizes the qsort partitioning process. */
-DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
+DUK_LOCAL void duk__debuglog_qsort_state(duk_hthread *thr, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
char buf[4096];
char *ptr = buf;
duk_int_t i, n;
- n = (duk_int_t) duk_get_length(ctx, 1);
+ n = (duk_int_t) duk_get_length(thr, 1);
if (n > 4000) {
n = 4000;
}
@@ -23749,15 +24903,15 @@ DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int
}
#endif
-DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
+DUK_LOCAL void duk__array_qsort(duk_hthread *thr, duk_int_t lo, duk_int_t hi) {
duk_int_t p, l, r;
/* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
- (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1)));
+ (long) lo, (long) hi, (duk_tval *) duk_get_tval(thr, 1)));
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
/* In some cases it may be that lo > hi, or hi < 0; these
* degenerate cases happen e.g. for empty arrays, and in
@@ -23773,14 +24927,14 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
DUK_ASSERT(hi - lo + 1 >= 2);
/* randomized pivot selection */
- p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE((duk_hthread *) ctx) * (duk_double_t) (hi - lo + 1));
+ p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE(thr) * (duk_double_t) (hi - lo + 1));
DUK_ASSERT(p >= lo && p <= hi);
DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p));
/* move pivot out of the way */
- duk__array_sort_swap(ctx, p, lo);
+ duk__array_sort_swap(thr, p, lo);
p = lo;
- DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
+ DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(thr, 1)));
l = lo + 1;
r = hi;
@@ -23792,7 +24946,7 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
if (l >= hi) {
break;
}
- if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */
+ if (duk__array_sort_compare(thr, l, p) >= 0) { /* !(l < p) */
break;
}
l++;
@@ -23803,7 +24957,7 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
if (r <= lo) {
break;
}
- if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */
+ if (duk__array_sort_compare(thr, p, r) >= 0) { /* !(p < r) */
break;
}
r--;
@@ -23815,9 +24969,9 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
- duk__array_sort_swap(ctx, l, r);
+ duk__array_sort_swap(thr, l, r);
- DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
+ DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
l++;
r--;
}
@@ -23833,25 +24987,25 @@ DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
*/
/* move pivot to its final place */
- DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_sort_swap(ctx, lo, r);
+ DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
+ duk__array_sort_swap(thr, lo, r);
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
- duk__debuglog_qsort_state(ctx, lo, hi, r);
+ duk__debuglog_qsort_state(thr, lo, hi, r);
#endif
- DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_qsort(ctx, lo, r - 1);
- duk__array_qsort(ctx, r + 1, hi);
+ DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(thr, 1)));
+ duk__array_qsort(thr, lo, r - 1);
+ duk__array_qsort(thr, r + 1, hi);
}
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_hthread *thr) {
duk_uint32_t len;
/* XXX: len >= 0x80000000 won't work below because a signed type
* is needed by qsort.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
+ len = duk__push_this_obj_len_u32_limited(thr);
/* stack[0] = compareFn
* stack[1] = ToObject(this)
@@ -23860,11 +25014,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
if (len > 0) {
/* avoid degenerate cases, so that (len - 1) won't underflow */
- duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1));
+ duk__array_qsort(thr, (duk_int_t) 0, (duk_int_t) (len - 1));
}
- DUK_ASSERT_TOP(ctx, 3);
- duk_pop(ctx);
+ DUK_ASSERT_TOP(thr, 3);
+ duk_pop_nodecref_unsafe(thr);
return 1; /* return ToObject(this) */
}
@@ -23881,9 +25035,10 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
* unshift is (close to?) <--> splice(0, 0, [items])?
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_hthread *thr) {
duk_idx_t nargs;
- duk_uint32_t len;
+ duk_uint32_t len_u32;
+ duk_int_t len;
duk_bool_t have_delcount;
duk_int_t item_count;
duk_int_t act_start;
@@ -23892,9 +25047,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
DUK_UNREF(have_delcount);
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
if (nargs < 2) {
- duk_set_top(ctx, 2);
+ duk_set_top(thr, 2);
nargs = 2;
have_delcount = 0;
} else {
@@ -23904,18 +25059,20 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
/* XXX: len >= 0x80000000 won't work below because we need to be
* able to represent -len.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
+ len_u32 = duk__push_this_obj_len_u32_limited(thr);
+ len = (duk_int_t) len_u32;
+ DUK_ASSERT(len >= 0);
- act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
+ act_start = duk_to_int_clamped(thr, 0, -len, len);
if (act_start < 0) {
act_start = len + act_start;
}
- DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
+ DUK_ASSERT(act_start >= 0 && act_start <= len);
#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
if (have_delcount) {
#endif
- del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
+ del_count = duk_to_int_clamped(thr, 1, 0, len - act_start);
#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
} else {
/* E5.1 standard behavior when deleteCount is not given would be
@@ -23930,16 +25087,16 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
DUK_ASSERT(nargs >= 2);
item_count = (duk_int_t) (nargs - 2);
- DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
- DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
+ DUK_ASSERT(del_count >= 0 && del_count <= len - act_start);
+ DUK_ASSERT(del_count + act_start <= len);
/* For now, restrict result array into 32-bit length range. */
if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
- DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
- duk_push_array(ctx);
+ duk_push_array(thr);
/* stack[0] = start
* stack[1] = deleteCount
@@ -23949,19 +25106,19 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* stack[nargs+2] = result array -1
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* Step 9: copy elements-to-be-deleted into the result array */
for (i = 0; i < del_count; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
- duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (act_start + i))) {
+ duk_xdef_prop_index_wec(thr, -2, (duk_uarridx_t) i); /* throw flag irrelevant (false in std alg) */
} else {
- duk_pop(ctx);
+ duk_pop_undefined(thr);
}
}
- duk_push_u32(ctx, (duk_uint32_t) del_count);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_u32(thr, (duk_uint32_t) del_count);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
/* Steps 12 and 13: reorganize elements to make room for itemCount elements */
@@ -23972,27 +25129,27 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C F G H ] (actual result at this point, C will be replaced)
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
n = len - del_count;
for (i = act_start; i < n; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
} else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
}
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* loop iterator init and limit changed from standard algorithm */
n = len - del_count + item_count;
for (i = len - 1; i >= n; i--) {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) i);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) i);
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
} else if (item_count > del_count) {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
* -> [ A B F G H ] (conceptual intermediate step)
@@ -24000,19 +25157,19 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C D E F F G H ] (actual result at this point)
*/
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* loop iterator init and limit changed from standard algorithm */
for (i = len - del_count - 1; i >= act_start; i--) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
+ if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
} else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
}
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
} else {
/* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
* -> [ A B F G H ] (conceptual intermediate step)
@@ -24020,24 +25177,24 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* [ A B C D E F G H ] (actual result at this point)
*/
}
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
/* Step 15: insert itemCount elements into the hole made above */
for (i = 0; i < item_count; i++) {
- duk_dup(ctx, i + 2); /* args start at index 2 */
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i));
+ duk_dup(thr, i + 2); /* args start at index 2 */
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) (act_start + i));
}
/* Step 16: update length; note that the final length may be above 32 bit range
* (but we checked above that this isn't the case here)
*/
- duk_push_u32(ctx, len - del_count + item_count);
- duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, (duk_uint32_t) (len - del_count + item_count));
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
/* result array is already at the top of stack */
- DUK_ASSERT_TOP(ctx, nargs + 3);
+ DUK_ASSERT_TOP(thr, nargs + 3);
return 1;
}
@@ -24045,13 +25202,13 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
* reverse()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t middle;
duk_uint32_t lower, upper;
duk_bool_t have_lower, have_upper;
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
middle = len / 2;
/* If len <= 1, middle will be 0 and for-loop bails out
@@ -24060,35 +25217,35 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
for (lower = 0; lower < middle; lower++) {
DUK_ASSERT(len >= 2);
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
DUK_ASSERT(len >= lower + 1);
upper = len - lower - 1;
- have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower);
- have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper);
+ have_lower = duk_get_prop_index(thr, -2, (duk_uarridx_t) lower);
+ have_upper = duk_get_prop_index(thr, -3, (duk_uarridx_t) upper);
/* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
if (have_upper) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower);
+ duk_put_prop_index(thr, -4, (duk_uarridx_t) lower);
} else {
- duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower);
- duk_pop(ctx);
+ duk_del_prop_index(thr, -4, (duk_uarridx_t) lower);
+ duk_pop_undefined(thr);
}
if (have_lower) {
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper);
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) upper);
} else {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper);
- duk_pop(ctx);
+ duk_del_prop_index(thr, -3, (duk_uarridx_t) upper);
+ duk_pop_undefined(thr);
}
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
}
- DUK_ASSERT_TOP(ctx, 2);
- duk_pop(ctx); /* -> [ ToObject(this) ] */
+ DUK_ASSERT_TOP(thr, 2);
+ duk_pop_unsafe(thr); /* -> [ ToObject(this) ] */
return 1;
}
@@ -24096,8 +25253,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
* slice()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
- duk_uint32_t len;
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_hthread *thr) {
+ duk_uint32_t len_u32;
+ duk_int_t len;
duk_int_t start, end;
duk_int_t i;
duk_uarridx_t idx;
@@ -24106,8 +25264,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
/* XXX: len >= 0x80000000 won't work below because we need to be
* able to represent -len.
*/
- len = duk__push_this_obj_len_u32_limited(ctx);
- duk_push_array(ctx);
+ len_u32 = duk__push_this_obj_len_u32_limited(thr);
+ len = (duk_int_t) len_u32;
+ DUK_ASSERT(len >= 0);
+
+ duk_push_array(thr);
/* stack[0] = start
* stack[1] = end
@@ -24116,41 +25277,41 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
* stack[4] = result array
*/
- start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
+ start = duk_to_int_clamped(thr, 0, -len, len);
if (start < 0) {
start = len + start;
}
/* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
* (the upper limit)?
*/
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
end = len;
} else {
- end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len);
+ end = duk_to_int_clamped(thr, 1, -len, len);
if (end < 0) {
end = len + end;
}
}
- DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
- DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
+ DUK_ASSERT(start >= 0 && start <= len);
+ DUK_ASSERT(end >= 0 && end <= len);
idx = 0;
for (i = start; i < end; i++) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- duk_xdef_prop_index_wec(ctx, 4, idx);
+ DUK_ASSERT_TOP(thr, 5);
+ if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
+ duk_xdef_prop_index_wec(thr, 4, idx);
res_length = idx + 1;
} else {
- duk_pop(ctx);
+ duk_pop_undefined(thr);
}
idx++;
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
}
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx_short(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ duk_push_u32(thr, res_length);
+ duk_xdef_prop_stridx_short(thr, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
return 1;
}
@@ -24158,18 +25319,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
* shift()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t i;
- len = duk__push_this_obj_len_u32(ctx);
+ len = duk__push_this_obj_len_u32(thr);
if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
return 0;
}
- duk_get_prop_index(ctx, 0, 0);
+ duk_get_prop_index(thr, 0, 0);
/* stack[0] = object (this)
* stack[1] = ToUint32(length)
@@ -24177,22 +25338,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
*/
for (i = 1; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 3);
- if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) {
+ DUK_ASSERT_TOP(thr, 3);
+ if (duk_get_prop_index(thr, 0, (duk_uarridx_t) i)) {
/* fromPresent = true */
- duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
+ duk_put_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
} else {
/* fromPresent = false */
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
- duk_pop(ctx);
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
+ duk_pop_undefined(thr);
}
}
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1));
+ duk_del_prop_index(thr, 0, (duk_uarridx_t) (len - 1));
- duk_push_u32(ctx, (duk_uint32_t) (len - 1));
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
+ duk_push_u32(thr, (duk_uint32_t) (len - 1));
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
return 1;
}
@@ -24200,20 +25361,20 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
* unshift()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_hthread *thr) {
duk_idx_t nargs;
duk_uint32_t len;
duk_uint32_t i;
- nargs = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
+ nargs = duk_get_top(thr);
+ len = duk__push_this_obj_len_u32(thr);
/* stack[0...nargs-1] = unshift args (vararg)
* stack[nargs] = ToObject(this)
* stack[nargs+1] = ToUint32(length)
*/
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
/* Note: unshift() may operate on indices above unsigned 32-bit range
* and the final length may be >= 2**32. However, we restrict the
@@ -24222,39 +25383,39 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
if (len + (duk_uint32_t) nargs < len) {
DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
- DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
+ DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
}
i = len;
while (i > 0) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
i--;
/* k+argCount-1; note that may be above 32-bit range */
- if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) {
+ if (duk_get_prop_index(thr, -2, (duk_uarridx_t) i)) {
/* fromPresent = true */
/* [ ... ToObject(this) ToUint32(length) val ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
} else {
/* fromPresent = false */
/* [ ... ToObject(this) ToUint32(length) val ] */
- duk_pop(ctx);
- duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
+ duk_pop_undefined(thr);
+ duk_del_prop_index(thr, -2, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
}
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
}
for (i = 0; i < (duk_uint32_t) nargs; i++) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) i);
- DUK_ASSERT_TOP(ctx, nargs + 2);
+ DUK_ASSERT_TOP(thr, nargs + 2);
+ duk_dup(thr, (duk_idx_t) i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
+ duk_put_prop_index(thr, -3, (duk_uarridx_t) i);
+ DUK_ASSERT_TOP(thr, nargs + 2);
}
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_push_u32(ctx, len + nargs);
- duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
- duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH);
+ DUK_ASSERT_TOP(thr, nargs + 2);
+ duk_push_u32(thr, len + (duk_uint32_t) nargs);
+ duk_dup_top(thr); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
return 1;
}
@@ -24262,22 +25423,22 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
* indexOf(), lastIndexOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_hthread *thr) {
duk_idx_t nargs;
duk_int_t i, len;
duk_int_t from_idx;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
+ duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
/* lastIndexOf() needs to be a vararg function because we must distinguish
* between an undefined fromIndex and a "not given" fromIndex; indexOf() is
* made vararg for symmetry although it doesn't strictly need to be.
*/
- nargs = duk_get_top(ctx);
- duk_set_top(ctx, 2);
+ nargs = duk_get_top(thr);
+ duk_set_top(thr, 2);
/* XXX: must be able to represent -len */
- len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx);
+ len = (duk_int_t) duk__push_this_obj_len_u32_limited(thr);
if (len == 0) {
goto not_found;
}
@@ -24304,7 +25465,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
* (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
*/
- from_idx = duk_to_int_clamped(ctx,
+ from_idx = duk_to_int_clamped(thr,
1,
(idx_step > 0 ? -len : -len - 1),
(idx_step > 0 ? len : len - 1));
@@ -24330,21 +25491,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
*/
for (i = from_idx; i >= 0 && i < len; i += idx_step) {
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_strict_equals(ctx, 0, 4)) {
- duk_push_int(ctx, i);
+ if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
+ DUK_ASSERT_TOP(thr, 5);
+ if (duk_strict_equals(thr, 0, 4)) {
+ duk_push_int(thr, i);
return 1;
}
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
not_found:
- duk_push_int(ctx, -1);
+ duk_push_int(thr, -1);
return 1;
}
@@ -24363,25 +25524,25 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
* 5 callers the net result is about 100 bytes / caller.
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) {
duk_uint32_t len;
duk_uint32_t i;
duk_uarridx_t k;
duk_bool_t bval;
- duk_small_int_t iter_type = duk_get_current_magic(ctx);
+ duk_small_int_t iter_type = duk_get_current_magic(thr);
duk_uint32_t res_length = 0;
/* each call this helper serves has nargs==2 */
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
- len = duk__push_this_obj_len_u32(ctx);
- duk_require_callable(ctx, 0);
+ len = duk__push_this_obj_len_u32(thr);
+ duk_require_callable(thr, 0);
/* if thisArg not supplied, behave as if undefined was supplied */
if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
- duk_push_array(ctx);
+ duk_push_array(thr);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
/* stack[0] = callback
@@ -24393,9 +25554,9 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
k = 0; /* result index for filter() */
for (i = 0; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
- if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
+ if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
/* Real world behavior for map(): trailing non-existent
* elements don't invoke the user callback, but are still
@@ -24410,7 +25571,7 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* counted towards result 'length'.
*/
#endif
- duk_pop(ctx);
+ duk_pop_undefined(thr);
continue;
}
@@ -24419,23 +25580,23 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* effects.
*/
- duk_dup_0(ctx);
- duk_dup_1(ctx);
- duk_dup_m3(ctx);
- duk_push_u32(ctx, i);
- duk_dup_2(ctx); /* [ ... val callback thisArg val i obj ] */
- duk_call_method(ctx, 3); /* -> [ ... val retval ] */
+ duk_dup_0(thr);
+ duk_dup_1(thr);
+ duk_dup_m3(thr);
+ duk_push_u32(thr, i);
+ duk_dup_2(thr); /* [ ... val callback thisArg val i obj ] */
+ duk_call_method(thr, 3); /* -> [ ... val retval ] */
switch (iter_type) {
case DUK__ITER_EVERY:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (!bval) {
/* stack top contains 'false' */
return 1;
}
break;
case DUK__ITER_SOME:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (bval) {
/* stack top contains 'true' */
return 1;
@@ -24445,15 +25606,15 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
/* nop */
break;
case DUK__ITER_MAP:
- duk_dup_top(ctx);
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */
+ duk_dup_top(thr);
+ duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) i); /* retval to result[i] */
res_length = i + 1;
break;
case DUK__ITER_FILTER:
- bval = duk_to_boolean(ctx, -1);
+ bval = duk_to_boolean(thr, -1);
if (bval) {
- duk_dup_m2(ctx); /* orig value */
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k);
+ duk_dup_m2(thr); /* orig value */
+ duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) k);
k++;
res_length = k;
}
@@ -24462,27 +25623,27 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
DUK_UNREACHABLE();
break;
}
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
}
switch (iter_type) {
case DUK__ITER_EVERY:
- duk_push_true(ctx);
+ duk_push_true(thr);
break;
case DUK__ITER_SOME:
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
case DUK__ITER_FOREACH:
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
break;
case DUK__ITER_MAP:
case DUK__ITER_FILTER:
- DUK_ASSERT_TOP(ctx, 5);
- DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
+ DUK_ASSERT_TOP(thr, 5);
+ DUK_ASSERT(duk_is_array(thr, -1)); /* topmost element is the result array already */
+ duk_push_u32(thr, res_length);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
break;
default:
DUK_UNREACHABLE();
@@ -24496,21 +25657,21 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
* reduce(), reduceRight()
*/
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_hthread *thr) {
duk_idx_t nargs;
duk_bool_t have_acc;
duk_uint32_t i, len;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */
+ duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for reduce, -1 for reduceRight */
/* We're a varargs function because we need to detect whether
* initialValue was given or not.
*/
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
- duk_set_top(ctx, 2);
- len = duk__push_this_obj_len_u32(ctx);
- duk_require_callable(ctx, 0);
+ duk_set_top(thr, 2);
+ len = duk__push_this_obj_len_u32(thr);
+ duk_require_callable(thr, 0);
/* stack[0] = callback fn
* stack[1] = initialValue
@@ -24521,11 +25682,11 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
have_acc = 0;
if (nargs >= 2) {
- duk_dup_1(ctx);
+ duk_dup_1(thr);
have_acc = 1;
}
DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
- (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));
+ (long) have_acc, (duk_tval *) duk_get_tval(thr, 3)));
/* For len == 0, i is initialized to len - 1 which underflows.
* The condition (i < len) will then exit the for-loop on the
@@ -24535,47 +25696,47 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
for (i = (idx_step >= 0 ? 0 : len - 1);
i < len; /* i >= 0 would always be true */
- i += idx_step) {
+ i += (duk_uint32_t) idx_step) {
DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
(long) i, (long) len, (long) have_acc,
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, 4)));
+ (long) duk_get_top(thr),
+ (duk_tval *) duk_get_tval(thr, 4)));
- DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
- (!have_acc && duk_get_top(ctx) == 4));
+ DUK_ASSERT((have_acc && duk_get_top(thr) == 5) ||
+ (!have_acc && duk_get_top(thr) == 4));
- if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
+ if (!duk_has_prop_index(thr, 2, (duk_uarridx_t) i)) {
continue;
}
if (!have_acc) {
- DUK_ASSERT_TOP(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
+ DUK_ASSERT_TOP(thr, 4);
+ duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
have_acc = 1;
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
} else {
- DUK_ASSERT_TOP(ctx, 5);
- duk_dup_0(ctx);
- duk_dup(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
- duk_push_u32(ctx, i);
- duk_dup_2(ctx);
+ DUK_ASSERT_TOP(thr, 5);
+ duk_dup_0(thr);
+ duk_dup(thr, 4);
+ duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
+ duk_push_u32(thr, i);
+ duk_dup_2(thr);
DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
- (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call(ctx, 4);
- DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, 4);
- DUK_ASSERT_TOP(ctx, 5);
+ (duk_tval *) duk_get_tval(thr, -5), (duk_tval *) duk_get_tval(thr, -4),
+ (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_call(thr, 4);
+ DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+ duk_replace(thr, 4);
+ DUK_ASSERT_TOP(thr, 5);
}
}
if (!have_acc) {
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
- DUK_ASSERT_TOP(ctx, 5);
+ DUK_ASSERT_TOP(thr, 5);
return 1;
}
@@ -24599,18 +25760,18 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
* the primitive value to stack top, and optionally coerces with ToString().
*/
-DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h;
- duk_small_int_t coerce_tostring = duk_get_current_magic(ctx);
+ duk_small_int_t coerce_tostring = duk_get_current_magic(thr);
/* XXX: there is room to use a shared helper here, many built-ins
* check the 'this' type, and if it's an object, check its class,
* then get its internal value, etc.
*/
- duk_push_this(ctx);
- tv = duk_get_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = duk_get_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BOOLEAN(tv)) {
@@ -24620,40 +25781,37 @@ DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx
DUK_ASSERT(h != NULL);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_boolean(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ DUK_ASSERT(duk_is_boolean(thr, -1));
goto type_ok;
}
}
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
/* never here */
type_ok:
if (coerce_tostring) {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) {
duk_hobject *h_this;
- DUK_UNREF(thr);
-
- duk_to_boolean(ctx, 0);
+ duk_to_boolean(thr, 0);
- if (duk_is_constructor_call(ctx)) {
+ if (duk_is_constructor_call(thr)) {
/* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
- duk_push_this(ctx);
- h_this = duk_known_hobject(ctx, -1);
+ duk_push_this(thr);
+ h_this = duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
- duk_dup_0(ctx); /* -> [ val obj val ] */
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
+ duk_dup_0(thr); /* -> [ val obj val ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
} /* unbalanced stack */
return 1;
@@ -24776,21 +25934,19 @@ static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
};
#endif /* !DUK_USE_PREFER_SIZE */
-DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_context *ctx) {
- duk_hthread *thr;
+DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_hthread *thr) {
duk_tval *tv_dst;
duk_hbufobj *res;
- thr = (duk_hthread *) ctx;
- duk_push_this(ctx);
- DUK_ASSERT(duk_is_buffer(ctx, -1));
- res = (duk_hbufobj *) duk_to_hobject(ctx, -1);
+ duk_push_this(thr);
+ DUK_ASSERT(duk_is_buffer(thr, -1));
+ res = (duk_hbufobj *) duk_to_hobject(thr, -1);
DUK_ASSERT_HBUFOBJ_VALID(res);
- DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(ctx, -1)));
+ DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(thr, -1)));
- tv_dst = duk_get_borrowed_this_tval(ctx);
+ tv_dst = duk_get_borrowed_this_tval(thr);
DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res);
- duk_pop(ctx);
+ duk_pop(thr);
return res;
}
@@ -24802,15 +25958,13 @@ DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_context *ctx) {
* always a duk_hbufobj *. Without the flag the return value can also be a
* plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER().
*/
-DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_context *ctx, duk_small_uint_t flags) {
- duk_hthread *thr;
+DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_uint_t flags) {
duk_tval *tv;
duk_hbufobj *h_this;
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+ DUK_ASSERT(thr != NULL);
- tv = duk_get_borrowed_this_tval(ctx);
+ tv = duk_get_borrowed_this_tval(thr);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
@@ -24829,7 +25983,7 @@ DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_context *ctx, duk_small_u
* support to avoid promotion.
*/
/* XXX: make this conditional to a flag if call sites need it? */
- h_this = duk__hbufobj_promote_this(ctx);
+ h_this = duk__hbufobj_promote_this(thr);
DUK_ASSERT(h_this != NULL);
DUK_ASSERT_HBUFOBJ_VALID(h_this);
return (duk_heaphdr *) h_this;
@@ -24846,29 +26000,26 @@ DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_context *ctx, duk_small_u
}
/* Check that 'this' is a duk_hbufobj and return a pointer to it. */
-DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_context *ctx) {
- return (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_PROMOTE);
+DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_hthread *thr) {
+ return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_PROMOTE);
}
/* Check that 'this' is a duk_hbufobj and return a pointer to it
* (NULL if not).
*/
-DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_context *ctx) {
- return (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE);
+DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_hthread *thr) {
+ return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE);
}
/* Check that value is a duk_hbufobj and return a pointer to it. */
-DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_context *ctx, duk_idx_t idx) {
- duk_hthread *thr;
+DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hbufobj *h_obj;
- thr = (duk_hthread *) ctx;
-
/* Don't accept relative indices now. */
DUK_ASSERT(idx >= 0);
- tv = duk_require_tval(ctx, idx);
+ tv = duk_require_tval(thr, idx);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
@@ -24878,7 +26029,7 @@ DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_context *ctx, duk_idx_t idx
return h_obj;
}
} else if (DUK_TVAL_IS_BUFFER(tv)) {
- h_obj = (duk_hbufobj *) duk_to_hobject(ctx, idx);
+ h_obj = (duk_hbufobj *) duk_to_hobject(thr, idx);
DUK_ASSERT(h_obj != NULL);
DUK_ASSERT_HBUFOBJ_VALID(h_obj);
return h_obj;
@@ -24888,17 +26039,13 @@ DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_context *ctx, duk_idx_t idx
return NULL; /* not reachable */
}
-DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
- duk_hthread *thr;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- DUK_ASSERT(ctx != NULL);
+DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
+ DUK_ASSERT(thr != NULL);
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
DUK_ASSERT(h_val != NULL);
DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
+ DUK_UNREF(thr);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
@@ -24911,23 +26058,19 @@ DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufobj *h_bufobj, d
}
/* Shared offset/length coercion helper. */
-DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
+DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr,
duk_hbufobj *h_bufarg,
duk_idx_t idx_offset,
duk_idx_t idx_length,
duk_uint_t *out_offset,
duk_uint_t *out_length,
duk_bool_t throw_flag) {
- duk_hthread *thr;
duk_int_t offset_signed;
duk_int_t length_signed;
duk_uint_t offset;
duk_uint_t length;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- offset_signed = duk_to_int(ctx, idx_offset);
+ offset_signed = duk_to_int(thr, idx_offset);
if (offset_signed < 0) {
goto fail_range;
}
@@ -24938,11 +26081,11 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
DUK_ASSERT(offset <= h_bufarg->length);
- if (duk_is_undefined(ctx, idx_length)) {
+ if (duk_is_undefined(thr, idx_length)) {
DUK_ASSERT(h_bufarg->length >= offset);
length = h_bufarg->length - offset; /* >= 0 */
} else {
- length_signed = duk_to_int(ctx, idx_length);
+ length_signed = duk_to_int(thr, idx_length);
if (length_signed < 0) {
goto fail_range;
}
@@ -24973,7 +26116,7 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
/* Shared lenient buffer length clamping helper. No negative indices, no
* element/byte shifting.
*/
-DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
+DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_hthread *thr,
duk_int_t buffer_length,
duk_idx_t idx_start,
duk_idx_t idx_end,
@@ -24986,11 +26129,11 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
DUK_ASSERT(out_end_offset != NULL);
/* undefined coerces to zero which is correct */
- start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length);
- if (duk_is_undefined(ctx, idx_end)) {
+ start_offset = duk_to_int_clamped(thr, idx_start, 0, buffer_length);
+ if (duk_is_undefined(thr, idx_end)) {
end_offset = buffer_length;
} else {
- end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length);
+ end_offset = duk_to_int_clamped(thr, idx_end, start_offset, buffer_length);
}
DUK_ASSERT(start_offset >= 0);
@@ -25010,7 +26153,7 @@ DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
* indices are clamped to zero length; and final indices are clamped
* against input slice. Used for e.g. ArrayBuffer slice().
*/
-DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
+DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_hthread *thr,
duk_int_t buffer_length,
duk_uint8_t buffer_shift,
duk_idx_t idx_start,
@@ -25030,14 +26173,14 @@ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
* indices first also avoids potential for wrapping.
*/
- start_offset = duk_to_int(ctx, idx_start);
+ start_offset = duk_to_int(thr, idx_start);
if (start_offset < 0) {
start_offset = buffer_length + start_offset;
}
- if (duk_is_undefined(ctx, idx_end)) {
+ if (duk_is_undefined(thr, idx_end)) {
end_offset = buffer_length;
} else {
- end_offset = duk_to_int(ctx, idx_end);
+ end_offset = duk_to_int(thr, idx_end);
if (end_offset < 0) {
end_offset = buffer_length + end_offset;
}
@@ -25068,45 +26211,41 @@ DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
*out_end_offset = end_offset;
}
-DUK_INTERNAL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx) {
- if (duk_is_buffer(ctx, idx)) {
- duk_to_object(ctx, idx);
+DUK_INTERNAL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx) {
+ if (duk_is_buffer(thr, idx)) {
+ duk_to_object(thr, idx);
}
}
DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) {
- duk_context *ctx;
-
- ctx = (duk_context *) thr;
-
/* Push Uint8Array which will share the same underlying buffer as
* the plain buffer argument. Also create an ArrayBuffer with the
* same backing for the result .buffer property.
*/
- duk_push_hbuffer(ctx, h_buf);
- duk_push_buffer_object(ctx, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY);
- duk_remove_m2(ctx);
+ duk_push_hbuffer(thr, h_buf);
+ duk_push_buffer_object(thr, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY);
+ duk_remove_m2(thr);
#if 0
/* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */
- h_bufobj = duk_push_bufobj_raw(ctx,
+ h_bufobj = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
DUK_BIDX_UINT8ARRAY_PROTOTYPE);
DUK_ASSERT(h_bufobj != NULL);
- duk__set_bufobj_buffer(ctx, h_bufobj, h_buf);
+ duk__set_bufobj_buffer(thr, h_bufobj, h_buf);
h_bufobj->is_typedarray = 1;
DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
- h_arrbuf = duk_push_bufobj_raw(ctx,
+ h_arrbuf = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
DUK_ASSERT(h_arrbuf != NULL);
- duk__set_bufobj_buffer(ctx, h_arrbuf, h_buf);
+ duk__set_bufobj_buffer(thr, h_arrbuf, h_buf);
DUK_ASSERT(h_arrbuf->is_typedarray == 0);
DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf);
@@ -25114,12 +26253,12 @@ DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_h
h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
DUK_ASSERT(h_arrbuf != NULL);
DUK_HBUFOBJ_INCREF(thr, h_arrbuf);
- duk_pop(ctx);
+ duk_pop(thr);
#endif
}
/* Indexed read helper for buffer objects, also called from outside this file. */
-DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
+DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
@@ -25127,28 +26266,28 @@ DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj
switch (h_bufobj->elem_type) {
case DUK_HBUFOBJ_ELEM_UINT8:
case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
- duk_push_uint(ctx, (duk_uint_t) du.uc[0]);
+ duk_push_uint(thr, (duk_uint_t) du.uc[0]);
break;
case DUK_HBUFOBJ_ELEM_INT8:
- duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]);
+ duk_push_int(thr, (duk_int_t) (duk_int8_t) du.uc[0]);
break;
case DUK_HBUFOBJ_ELEM_UINT16:
- duk_push_uint(ctx, (duk_uint_t) du.us[0]);
+ duk_push_uint(thr, (duk_uint_t) du.us[0]);
break;
case DUK_HBUFOBJ_ELEM_INT16:
- duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]);
+ duk_push_int(thr, (duk_int_t) (duk_int16_t) du.us[0]);
break;
case DUK_HBUFOBJ_ELEM_UINT32:
- duk_push_uint(ctx, (duk_uint_t) du.ui[0]);
+ duk_push_uint(thr, (duk_uint_t) du.ui[0]);
break;
case DUK_HBUFOBJ_ELEM_INT32:
- duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]);
+ duk_push_int(thr, (duk_int_t) (duk_int32_t) du.ui[0]);
break;
case DUK_HBUFOBJ_ELEM_FLOAT32:
- duk_push_number(ctx, (duk_double_t) du.f[0]);
+ duk_push_number(thr, (duk_double_t) du.f[0]);
break;
case DUK_HBUFOBJ_ELEM_FLOAT64:
- duk_push_number(ctx, (duk_double_t) du.d);
+ duk_push_number(thr, (duk_double_t) du.d);
break;
default:
DUK_UNREACHABLE();
@@ -25156,7 +26295,7 @@ DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj
}
/* Indexed write helper for buffer objects, also called from outside this file. */
-DUK_INTERNAL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
+DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
/* NOTE! Caller must ensure that any side effects from the
@@ -25169,31 +26308,31 @@ DUK_INTERNAL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_b
switch (h_bufobj->elem_type) {
case DUK_HBUFOBJ_ELEM_UINT8:
- du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1);
+ du.uc[0] = (duk_uint8_t) duk_to_uint32(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
- du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1);
+ du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_INT8:
- du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1);
+ du.uc[0] = (duk_uint8_t) duk_to_int32(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_UINT16:
- du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1);
+ du.us[0] = (duk_uint16_t) duk_to_uint32(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_INT16:
- du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1);
+ du.us[0] = (duk_uint16_t) duk_to_int32(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_UINT32:
- du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1);
+ du.ui[0] = (duk_uint32_t) duk_to_uint32(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_INT32:
- du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1);
+ du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_FLOAT32:
- du.f[0] = (duk_float_t) duk_to_number_m1(ctx);
+ du.f[0] = (duk_float_t) duk_to_number_m1(thr);
break;
case DUK_HBUFOBJ_ELEM_FLOAT64:
- du.d = (duk_double_t) duk_to_number_m1(ctx);
+ du.d = (duk_double_t) duk_to_number_m1(thr);
break;
default:
DUK_UNREACHABLE();
@@ -25205,16 +26344,16 @@ DUK_INTERNAL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_b
/* Helper to create a fixed buffer from argument value at index 0.
* Node.js and allocPlain() compatible.
*/
-DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_context *ctx) {
+DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) {
duk_int_t len;
duk_int_t i;
duk_size_t buf_size;
duk_uint8_t *buf;
- switch (duk_get_type(ctx, 0)) {
+ switch (duk_get_type(thr, 0)) {
case DUK_TYPE_NUMBER: {
- len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX);
- (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len);
+ len = duk_to_int_clamped(thr, 0, 0, DUK_INT_MAX);
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
break;
}
case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */
@@ -25229,51 +26368,51 @@ DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_context *ctx) {
* https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe
*/
- h = duk_known_hobject(ctx, 0);
+ h = duk_known_hobject(thr, 0);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h));
h_bufobj = (duk_hbufobj *) h;
if (DUK_UNLIKELY(h_bufobj->buf == NULL)) {
- DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) {
/* No support for ArrayBuffers with slice
* offset/length.
*/
- DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
- duk_push_hbuffer(ctx, h_bufobj->buf);
+ duk_push_hbuffer(thr, h_bufobj->buf);
return h_bufobj->buf;
}
goto slow_copy;
}
case DUK_TYPE_STRING: {
/* ignore encoding for now */
- duk_require_hstring_notsymbol(ctx, 0);
- duk_dup_0(ctx);
- (void) duk_to_buffer(ctx, -1, &buf_size);
+ duk_require_hstring_notsymbol(thr, 0);
+ duk_dup_0(thr);
+ (void) duk_to_buffer(thr, -1, &buf_size);
break;
}
default:
- DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
done:
- DUK_ASSERT(duk_is_buffer(ctx, -1));
- return duk_known_hbuffer(ctx, -1);
+ DUK_ASSERT(duk_is_buffer(thr, -1));
+ return duk_known_hbuffer(thr, -1);
slow_copy:
/* XXX: fast path for typed arrays and other buffer objects? */
- (void) duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
- len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX);
- duk_pop(ctx);
- buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) len); /* no zeroing, all indices get initialized */
+ (void) duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
+ len = duk_to_int_clamped(thr, -1, 0, DUK_INT_MAX);
+ duk_pop(thr);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); /* no zeroing, all indices get initialized */
for (i = 0; i < len; i++) {
/* XXX: fast path for array or buffer arguments? */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU);
- duk_pop(ctx);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ buf[i] = (duk_uint8_t) (duk_to_uint32(thr, -1) & 0xffU);
+ duk_pop(thr);
}
goto done;
}
@@ -25288,19 +26427,19 @@ DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_context *ctx) {
* constructor entry point is used.
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) {
duk_hbuffer *h_buf;
- h_buf = duk__hbufobj_fixed_from_argvalue(ctx);
+ h_buf = duk__hbufobj_fixed_from_argvalue(thr);
DUK_ASSERT(h_buf != NULL);
- duk_push_buffer_object(ctx,
+ duk_push_buffer_object(thr,
-1,
0,
DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf),
DUK_BUFOBJ_UINT8ARRAY);
- duk_push_hobject_bidx(ctx, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
- duk_set_prototype(ctx, -2);
+ duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
+ duk_set_prototype(thr, -2);
/* XXX: a more direct implementation */
@@ -25313,33 +26452,30 @@ 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_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_hthread *thr) {
duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
duk_int_t len;
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
+ DUK_ASSERT_CTX_VALID(thr);
- duk_require_constructor_call(ctx);
+ duk_require_constructor_call(thr);
- len = duk_to_int(ctx, 0);
+ len = duk_to_int(thr, 0);
if (len < 0) {
goto fail_length;
}
- (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len);
- h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1);
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
+ h_val = (duk_hbuffer *) duk_known_hbuffer(thr, -1);
- h_bufobj = duk_push_bufobj_raw(ctx,
+ h_bufobj = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
DUK_ASSERT(h_bufobj != NULL);
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
+ duk__set_bufobj_buffer(thr, h_bufobj, h_val);
DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
@@ -25358,8 +26494,7 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h_obj;
duk_hbufobj *h_bufobj = NULL;
@@ -25377,24 +26512,21 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
duk_uint_t byte_length;
duk_small_uint_t copy_mode;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
/* XXX: The same copy helpers could be shared with at least some
* buffer functions.
*/
- duk_require_constructor_call(ctx);
+ duk_require_constructor_call(thr);
/* We could fit built-in index into magic but that'd make the magic
* number dependent on built-in numbering (genbuiltins.py doesn't
* handle that yet). So map both class and prototype from the
* element type.
*/
- magic = duk_get_current_magic(ctx);
- shift = magic & 0x03; /* bits 0...1: shift */
- elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */
- elem_size = 1 << shift;
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
+ shift = magic & 0x03U; /* bits 0...1: shift */
+ elem_type = (magic >> 2) & 0x0fU; /* bits 2...5: type */
+ elem_size = 1U << shift;
align_mask = elem_size - 1;
DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
@@ -25416,9 +26548,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* coerce to an ArrayBuffer object and use that as .buffer. The underlying
* buffer will be the same but result .buffer !== inputPlainBuffer.
*/
- duk_hbufobj_promote_plain(ctx, 0);
+ duk_hbufobj_promote_plain(thr, 0);
- tv = duk_get_tval(ctx, 0);
+ tv = duk_get_tval(thr, 0);
DUK_ASSERT(tv != NULL); /* arg count */
if (DUK_TVAL_IS_OBJECT(tv)) {
h_obj = DUK_TVAL_GET_OBJECT(tv);
@@ -25434,7 +26566,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
h_bufarg = (duk_hbufobj *) h_obj;
- byte_offset_signed = duk_to_int(ctx, 1);
+ byte_offset_signed = duk_to_int(thr, 1);
if (byte_offset_signed < 0) {
goto fail_arguments;
}
@@ -25444,7 +26576,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* Must be >= 0 and multiple of element size. */
goto fail_arguments;
}
- if (duk_is_undefined(ctx, 2)) {
+ if (duk_is_undefined(thr, 2)) {
DUK_ASSERT(h_bufarg->length >= byte_offset);
byte_length = h_bufarg->length - byte_offset;
if ((byte_length & align_mask) != 0) {
@@ -25455,7 +26587,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
}
elem_length = (byte_length >> shift);
} else {
- elem_length_signed = duk_to_int(ctx, 2);
+ elem_length_signed = duk_to_int(thr, 2);
if (elem_length_signed < 0) {
goto fail_arguments;
}
@@ -25479,11 +26611,11 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
DUK_ASSERT((elem_length << shift) == byte_length);
- h_bufobj = duk_push_bufobj_raw(ctx,
+ h_bufobj = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
+ (duk_small_int_t) proto_bidx);
h_val = h_bufarg->buf;
if (h_val == NULL) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
@@ -25548,7 +26680,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
#endif /* !DUK_USE_PREFER_SIZE */
} else {
/* Array or Array-like */
- elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
+ elem_length_signed = (duk_int_t) duk_get_length(thr, 0);
copy_mode = 2;
}
} else {
@@ -25556,7 +26688,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* V8 behavior (except for "null", which we coerce to
* 0 but V8 TypeErrors).
*/
- elem_length_signed = duk_to_int(ctx, 0);
+ elem_length_signed = duk_to_int(thr, 0);
copy_mode = 3;
}
if (elem_length_signed < 0) {
@@ -25582,15 +26714,15 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
*/
/* Push the resulting view object on top of a plain fixed buffer. */
- (void) duk_push_fixed_buffer(ctx, byte_length);
- h_val = duk_known_hbuffer(ctx, -1);
+ (void) duk_push_fixed_buffer(thr, byte_length);
+ h_val = duk_known_hbuffer(thr, -1);
DUK_ASSERT(h_val != NULL);
- h_bufobj = duk_push_bufobj_raw(ctx,
+ h_bufobj = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
+ (duk_small_int_t) proto_bidx);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
@@ -25651,7 +26783,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_ASSERT(h_bufarg->buf != NULL);
DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
- src_elem_size = 1 << h_bufarg->shift;
+ src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
dst_elem_size = elem_size;
p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
@@ -25670,9 +26802,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
/* A validated read() is always a number, so it's write coercion
* is always side effect free an won't invalidate pointers etc.
*/
- duk_hbufobj_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufobj_validated_write(ctx, h_bufobj, p_dst, dst_elem_size);
- duk_pop(ctx);
+ duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
+ duk_hbufobj_validated_write(thr, h_bufobj, p_dst, dst_elem_size);
+ duk_pop(thr);
p_src += src_elem_size;
p_dst += dst_elem_size;
}
@@ -25688,8 +26820,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("using slow copy"));
for (i = 0; i < elem_length; i++) {
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- duk_put_prop_index(ctx, -2, (duk_uarridx_t) i);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) i);
}
break;
}
@@ -25715,7 +26847,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* supported to create a plain fixed buffer. Disabled for now.
*/
#if 0
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
duk_int_t elem_length_signed;
duk_uint_t byte_length;
@@ -25723,44 +26855,44 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
* buffer functions.
*/
- duk_require_constructor_call(ctx);
+ duk_require_constructor_call(thr);
- elem_length_signed = duk_require_int(ctx, 0);
+ elem_length_signed = duk_require_int(thr, 0);
if (elem_length_signed < 0) {
goto fail_arguments;
}
byte_length = (duk_uint_t) elem_length_signed;
- (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) byte_length);
+ (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) byte_length);
return 1;
fail_arguments:
- DUK_DCERROR_RANGE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* 0 */
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_hthread *thr) {
duk_hbufobj *h_bufarg;
duk_hbufobj *h_bufobj;
duk_hbuffer *h_val;
duk_uint_t offset;
duk_uint_t length;
- duk_require_constructor_call(ctx);
+ duk_require_constructor_call(thr);
- h_bufarg = duk__require_bufobj_value(ctx, 0);
+ h_bufarg = duk__require_bufobj_value(thr, 0);
DUK_ASSERT(h_bufarg != NULL);
if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
- duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
+ duk__resolve_offset_opt_length(thr, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
DUK_ASSERT(offset <= h_bufarg->length);
DUK_ASSERT(offset + length <= h_bufarg->length);
- h_bufobj = duk_push_bufobj_raw(ctx,
+ h_bufobj = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
@@ -25768,7 +26900,7 @@ DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
h_val = h_bufarg->buf;
if (h_val == NULL) {
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
@@ -25781,7 +26913,7 @@ DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
DUK_ASSERT(h_bufobj->buf_prop == NULL);
h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
DUK_ASSERT(h_bufarg != NULL);
- DUK_HBUFOBJ_INCREF((duk_hthread *) ctx, h_bufarg);
+ DUK_HBUFOBJ_INCREF(thr, h_bufarg);
DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
return 1;
@@ -25793,14 +26925,14 @@ DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_hthread *thr) {
duk_hobject *h_obj;
duk_bool_t ret = 0;
- if (duk_is_buffer(ctx, 0)) {
+ if (duk_is_buffer(thr, 0)) {
ret = 1;
} else {
- h_obj = duk_get_hobject(ctx, 0);
+ h_obj = duk_get_hobject(thr, 0);
if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
/* DataView needs special casing: ArrayBuffer.isView() is
* true, but ->is_typedarray is 0.
@@ -25809,7 +26941,7 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
(DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW);
}
}
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -25819,8 +26951,8 @@ DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx) {
- duk__hbufobj_fixed_from_argvalue(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_hthread *thr) {
+ duk__hbufobj_fixed_from_argvalue(thr);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -25830,12 +26962,12 @@ DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_hthread *thr) {
duk_hbufobj *h_bufobj;
#if !defined(DUK_USE_PREFER_SIZE)
/* Avoid churn if argument is already a plain buffer. */
- if (duk_is_buffer(ctx, 0)) {
+ if (duk_is_buffer(thr, 0)) {
return 1;
}
#endif
@@ -25844,11 +26976,11 @@ DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx) {
* argument we'll create a pointless temporary (but still work
* correctly).
*/
- h_bufobj = duk__require_bufobj_value(ctx, 0);
+ h_bufobj = duk__require_bufobj_value(thr, 0);
if (h_bufobj->buf == NULL) {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
} else {
- duk_push_hbuffer(ctx, h_bufobj->buf);
+ duk_push_hbuffer(thr, h_bufobj->buf);
}
return 1;
}
@@ -25859,27 +26991,23 @@ DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
duk_hbufobj *h_this;
duk_int_t start_offset, end_offset;
duk_uint8_t *buf_slice;
duk_size_t slice_length;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__get_bufobj_this(ctx);
+ h_this = duk__get_bufobj_this(thr);
if (h_this == NULL) {
/* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
- duk_push_string(ctx, "[object Object]");
+ duk_push_string(thr, "[object Object]");
return 1;
}
DUK_ASSERT_HBUFOBJ_VALID(h_this);
/* Ignore encoding for now. */
- duk__clamp_startend_nonegidx_noshift(ctx,
+ duk__clamp_startend_nonegidx_noshift(thr,
(duk_int_t) h_this->length,
1 /*idx_start*/,
2 /*idx_end*/,
@@ -25887,12 +27015,12 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
&end_offset);
slice_length = (duk_size_t) (end_offset - start_offset);
- buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, slice_length); /* all bytes initialized below */
+ buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, slice_length); /* all bytes initialized below */
DUK_ASSERT(buf_slice != NULL);
/* Neutered or uncovered, TypeError. */
if (h_this->buf == NULL ||
- !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
+ !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
@@ -25902,7 +27030,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
* its stability is difficult).
*/
- DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length));
+ DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length));
DUK_MEMCPY((void *) buf_slice,
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
(size_t) slice_length);
@@ -25911,9 +27039,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
* string. Result will be valid UTF-8; non-CESU-8 inputs are currently
* interpreted loosely. Value stack convention is a bit odd for now.
*/
- duk_replace(ctx, 0);
- duk_set_top(ctx, 1);
- return duk_textdecoder_decode_utf8_nodejs(ctx);
+ duk_replace(thr, 0);
+ duk_set_top(thr, 1);
+ return duk_textdecoder_decode_utf8_nodejs(thr);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -25922,44 +27050,37 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_hthread *thr) {
duk_hbufobj *h_this;
- duk_harray *h_arr;
duk_uint8_t *buf;
duk_uint_t i, n;
duk_tval *tv;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) {
/* Serialize uncovered backing buffer as a null; doesn't
* really matter as long we're memory safe.
*/
- duk_push_null(ctx);
+ duk_push_null(thr);
return 1;
}
- duk_push_object(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER);
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_TYPE);
+ duk_push_object(thr);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_BUFFER);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_TYPE);
+ /* XXX: uninitialized would be OK */
DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX);
- h_arr = duk_push_harray_with_size(ctx, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */
- DUK_ASSERT(h_arr != NULL);
- DUK_ASSERT(h_arr->length == h_this->length);
- tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
+ tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */
DUK_ASSERT(h_this->buf != NULL);
buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
for (i = 0, n = h_this->length; i < n; i++) {
DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */
}
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_DATA);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_DATA);
return 1;
}
@@ -25972,26 +27093,22 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_hthread *thr) {
duk_small_uint_t magic;
duk_hbufobj *h_bufarg1;
duk_hbufobj *h_bufarg2;
duk_small_int_t comp_res;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
/* XXX: keep support for plain buffers and non-Node.js buffers? */
- magic = duk_get_current_magic(ctx);
- if (magic & 0x02) {
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
+ if (magic & 0x02U) {
/* Static call style. */
- h_bufarg1 = duk__require_bufobj_value(ctx, 0);
- h_bufarg2 = duk__require_bufobj_value(ctx, 1);
+ h_bufarg1 = duk__require_bufobj_value(thr, 0);
+ h_bufarg2 = duk__require_bufobj_value(thr, 1);
} else {
- h_bufarg1 = duk__require_bufobj_this(ctx);
- h_bufarg2 = duk__require_bufobj_value(ctx, 0);
+ h_bufarg1 = duk__require_bufobj_this(thr);
+ h_bufarg2 = duk__require_bufobj_value(thr, 0);
}
DUK_ASSERT(h_bufarg1 != NULL);
DUK_ASSERT(h_bufarg2 != NULL);
@@ -26012,12 +27129,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
comp_res = -1; /* either nonzero value is ok */
}
- if (magic & 0x01) {
+ if (magic & 0x01U) {
/* compare: similar to string comparison but for buffer data. */
- duk_push_int(ctx, comp_res);
+ duk_push_int(thr, comp_res);
} else {
/* equals */
- duk_push_boolean(ctx, (comp_res == 0));
+ duk_push_boolean(thr, (comp_res == 0));
}
return 1;
@@ -26029,8 +27146,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) {
duk_hbufobj *h_this;
const duk_uint8_t *fill_str_ptr;
duk_size_t fill_str_len;
@@ -26040,10 +27156,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
duk_size_t fill_length;
duk_uint8_t *p;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
if (h_this->buf == NULL) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
@@ -26051,19 +27164,19 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
/* [ value offset end ] */
- if (duk_is_string_notsymbol(ctx, 0)) {
- fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len);
+ if (duk_is_string_notsymbol(thr, 0)) {
+ fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(thr, 0, &fill_str_len);
DUK_ASSERT(fill_str_ptr != NULL);
} else {
/* Symbols get ToNumber() coerced and cause TypeError. */
- fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0);
+ fill_value = (duk_uint8_t) duk_to_uint32(thr, 0);
fill_str_ptr = (const duk_uint8_t *) &fill_value;
fill_str_len = 1;
}
/* Fill offset handling is more lenient than in Node.js. */
- duk__clamp_startend_nonegidx_noshift(ctx,
+ duk__clamp_startend_nonegidx_noshift(thr,
(duk_int_t) h_this->length,
1 /*idx_start*/,
2 /*idx_end*/,
@@ -26086,7 +27199,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
} else if (fill_str_len > 1) {
duk_size_t i, n, t;
- for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) {
+ for (i = 0, n = (duk_size_t) (fill_end - fill_offset), t = 0; i < n; i++) {
p[i] = fill_str_ptr[t++];
if (t >= fill_str_len) {
t = 0;
@@ -26097,7 +27210,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
}
/* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
- duk_push_this(ctx);
+ duk_push_this(thr);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -26107,25 +27220,21 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) {
duk_hbufobj *h_this;
duk_uint_t offset;
duk_uint_t length;
const duk_uint8_t *str_data;
duk_size_t str_len;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
/* XXX: very inefficient support for plain buffers */
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
/* Argument must be a string, e.g. a buffer is not allowed. */
- str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(ctx, 0, &str_len);
+ str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(thr, 0, &str_len);
- duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
+ duk__resolve_offset_opt_length(thr, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
DUK_ASSERT(offset <= h_this->length);
DUK_ASSERT(offset + length <= h_this->length);
@@ -26144,7 +27253,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
}
- duk_push_uint(ctx, length);
+ duk_push_uint(thr, length);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -26154,8 +27263,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) {
duk_hbufobj *h_this;
duk_hbufobj *h_bufarg;
duk_int_t source_length;
@@ -26166,22 +27274,19 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
/* [ targetBuffer targetStart sourceStart sourceEnd ] */
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
- h_bufarg = duk__require_bufobj_value(ctx, 0);
+ h_this = duk__require_bufobj_this(thr);
+ h_bufarg = duk__require_bufobj_value(thr, 0);
DUK_ASSERT(h_this != NULL);
DUK_ASSERT(h_bufarg != NULL);
source_length = (duk_int_t) h_this->length;
target_length = (duk_int_t) h_bufarg->length;
- target_start = duk_to_int(ctx, 1);
- source_start = duk_to_int(ctx, 2);
- if (duk_is_undefined(ctx, 3)) {
+ target_start = duk_to_int(thr, 1);
+ source_start = duk_to_int(thr, 2);
+ if (duk_is_undefined(thr, 3)) {
source_end = source_length;
} else {
- source_end = duk_to_int(ctx, 3);
+ source_end = duk_to_int(thr, 3);
}
DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
@@ -26205,7 +27310,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
}
if (source_uend >= (duk_uint_t) source_length) {
/* Source end clamped silently to available length. */
- source_uend = source_length;
+ source_uend = (duk_uint_t) source_length;
}
copy_size = source_uend - source_ustart;
if (target_ustart + copy_size > (duk_uint_t) target_length) {
@@ -26251,7 +27356,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
* The return value matters because of code like:
* "off += buf.copy(...)".
*/
- duk_push_uint(ctx, copy_size);
+ duk_push_uint(thr, copy_size);
return 1;
fail_bounds:
@@ -26296,8 +27401,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
duk_hbufobj *h_this;
duk_hobject *h_obj;
duk_uarridx_t i, n;
@@ -26305,10 +27409,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
duk_uint_t offset_elems;
duk_uint_t offset_bytes;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
DUK_ASSERT(h_this != NULL);
DUK_ASSERT_HBUFOBJ_VALID(h_this);
@@ -26317,14 +27418,14 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
return 0;
}
- duk_hbufobj_promote_plain(ctx, 0);
- h_obj = duk_require_hobject(ctx, 0);
+ duk_hbufobj_promote_plain(thr, 0);
+ h_obj = duk_require_hobject(thr, 0);
/* XXX: V8 throws a TypeError for negative values. Would it
* be more useful to interpret negative offsets here from the
* end of the buffer too?
*/
- offset_signed = duk_to_int(ctx, 1);
+ offset_signed = duk_to_int(thr, 1);
if (offset_signed < 0) {
/* For some reason this is a TypeError (at least in V8). */
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
@@ -26472,7 +27573,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
duk_uint8_t *p_src_copy;
DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
- p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, src_length);
+ p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length);
DUK_ASSERT(p_src_copy != NULL);
DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
@@ -26484,7 +27585,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
"p_dst_base=%p, dst_length=%ld, valstack top=%ld",
(void *) p_src_base, (long) src_length,
(void *) p_dst_base, (long) dst_length,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
/* Ready to make the copy. We must proceed element by element
* and must avoid any side effects that might cause the buffer
@@ -26494,8 +27595,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* numbers are handled which should be side effect safe.
*/
- src_elem_size = 1 << h_bufarg->shift;
- dst_elem_size = 1 << h_this->shift;
+ src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
+ dst_elem_size = (duk_small_uint_t) (1U << h_this->shift);
p_src = p_src_base;
p_dst = p_dst_base;
p_src_end = p_src_base + src_length;
@@ -26507,9 +27608,9 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
/* A validated read() is always a number, so it's write coercion
* is always side effect free an won't invalidate pointers etc.
*/
- duk_hbufobj_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufobj_validated_write(ctx, h_this, p_dst, dst_elem_size);
- duk_pop(ctx);
+ duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
+ duk_hbufobj_validated_write(thr, h_this, p_dst, dst_elem_size);
+ duk_pop(thr);
p_src += src_elem_size;
p_dst += dst_elem_size;
}
@@ -26525,7 +27626,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* would be needed for every element anyway.
*/
- n = (duk_uarridx_t) duk_get_length(ctx, 0);
+ n = (duk_uarridx_t) duk_get_length(thr, 0);
DUK_ASSERT(offset_bytes <= h_this->length);
if ((n << h_this->shift) > h_this->length - offset_bytes) {
/* Overflow not an issue because subtraction is used on the right
@@ -26542,12 +27643,12 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
* the results anyway.
*/
- DUK_ASSERT_TOP(ctx, 2);
- duk_push_this(ctx);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_push_this(thr);
for (i = 0; i < n; i++) {
- duk_get_prop_index(ctx, 0, i);
- duk_put_prop_index(ctx, 2, offset_elems + i);
+ duk_get_prop_index(thr, 0, i);
+ duk_put_prop_index(thr, 2, offset_elems + i);
}
}
@@ -26579,17 +27680,13 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_LOCAL void duk__arraybuffer_plain_slice(duk_context *ctx, duk_hbuffer *h_val) {
- duk_hthread *thr;
+DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val) {
duk_int_t start_offset, end_offset;
duk_uint_t slice_length;
duk_uint8_t *p_copy;
duk_size_t copy_length;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- duk__clamp_startend_negidx_shifted(ctx,
+ duk__clamp_startend_negidx_shifted(thr,
(duk_int_t) DUK_HBUFFER_GET_SIZE(h_val),
0 /*buffer_shift*/,
0 /*idx_start*/,
@@ -26601,7 +27698,7 @@ DUK_LOCAL void duk__arraybuffer_plain_slice(duk_context *ctx, duk_hbuffer *h_val
DUK_ASSERT(end_offset >= start_offset);
slice_length = (duk_uint_t) (end_offset - start_offset);
- p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) slice_length);
+ p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) slice_length);
DUK_ASSERT(p_copy != NULL);
copy_length = slice_length;
@@ -26615,8 +27712,7 @@ DUK_LOCAL void duk__arraybuffer_plain_slice(duk_context *ctx, duk_hbuffer *h_val
/* Shared helper for slice/subarray operation.
* Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling.
*/
-DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) {
duk_small_int_t magic;
duk_small_uint_t res_class_num;
duk_small_int_t res_proto_bidx;
@@ -26627,14 +27723,11 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
duk_uint_t slice_length;
duk_tval *tv;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
/* [ start end ] */
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
- tv = duk_get_borrowed_this_tval(ctx);
+ tv = duk_get_borrowed_this_tval(thr);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BUFFER(tv)) {
@@ -26644,7 +27737,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
if (magic & 0x02) {
/* Make copy: ArrayBuffer.prototype.slice() uses this. */
- duk__arraybuffer_plain_slice(ctx, h_val);
+ duk__arraybuffer_plain_slice(thr, h_val);
return 1;
} else {
/* View into existing buffer: cannot be done if the
@@ -26661,7 +27754,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
}
tv = NULL; /* No longer valid nor needed. */
- h_this = duk__require_bufobj_this(ctx);
+ h_this = duk__require_bufobj_this(thr);
/* Slice offsets are element (not byte) offsets, which only matters
* for TypedArray views, Node.js Buffer and ArrayBuffer have shift
@@ -26672,7 +27765,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
* against the underlying buffer here.
*/
- duk__clamp_startend_negidx_shifted(ctx,
+ duk__clamp_startend_negidx_shifted(thr,
(duk_int_t) h_this->length,
(duk_uint8_t) h_this->shift,
0 /*idx_start*/,
@@ -26680,6 +27773,8 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
&start_offset,
&end_offset);
DUK_ASSERT(end_offset >= start_offset);
+ DUK_ASSERT(start_offset >= 0);
+ DUK_ASSERT(end_offset >= 0);
slice_length = (duk_uint_t) (end_offset - start_offset);
/* The resulting buffer object gets the same class and prototype as
@@ -26701,14 +27796,14 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
if (magic & 0x04) {
res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE;
}
- h_bufobj = duk_push_bufobj_raw(ctx,
+ h_bufobj = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
res_proto_bidx);
DUK_ASSERT(h_bufobj != NULL);
- h_bufobj->length = slice_length;
+ DUK_ASSERT(h_bufobj->length == 0);
h_bufobj->shift = h_this->shift; /* inherit */
h_bufobj->elem_type = h_this->elem_type; /* inherit */
h_bufobj->is_typedarray = magic & 0x01;
@@ -26724,7 +27819,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
duk_uint8_t *p_copy;
duk_size_t copy_length;
- p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(ctx, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */
+ p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */
DUK_ASSERT(p_copy != NULL);
/* Copy slice, respecting underlying buffer limits; remainder
@@ -26735,17 +27830,19 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
(const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
copy_length);
- h_val = duk_known_hbuffer(ctx, -1);
+ h_val = duk_known_hbuffer(thr, -1);
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
+ h_bufobj->length = slice_length;
DUK_ASSERT(h_bufobj->offset == 0);
- duk_pop(ctx); /* reachable so pop OK */
+ duk_pop(thr); /* reachable so pop OK */
} else {
h_bufobj->buf = h_val;
DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset);
+ h_bufobj->length = slice_length;
+ h_bufobj->offset = h_this->offset + (duk_uint_t) start_offset;
/* Copy the .buffer property, needed for TypedArray.prototype.subarray().
*
@@ -26768,14 +27865,14 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_hthread *thr) {
const char *encoding;
/* only accept lowercase 'utf8' now. */
- encoding = duk_to_string(ctx, 0);
- DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */
- duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0);
+ encoding = duk_to_string(thr, 0);
+ DUK_ASSERT(duk_is_string(thr, 0)); /* guaranteed by duk_to_string() */
+ duk_push_boolean(thr, DUK_STRCMP(encoding, "utf8") == 0);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -26785,16 +27882,13 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_hthread *thr) {
duk_hobject *h;
duk_hobject *h_proto;
duk_bool_t ret = 0;
- thr = (duk_hthread *) ctx;
-
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */
- h = duk_get_hobject(ctx, 0);
+ DUK_ASSERT(duk_get_top(thr) >= 1); /* nargs */
+ h = duk_get_hobject(thr, 0);
if (h != NULL) {
h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
DUK_ASSERT(h_proto != NULL);
@@ -26805,7 +27899,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
}
}
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -26815,7 +27909,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_hthread *thr) {
const char *str;
duk_size_t len;
@@ -26834,9 +27928,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
* (The 20 comes from '[object Uint32Array]'.length
*/
- str = duk_to_lstring(ctx, 0, &len);
+ str = duk_to_lstring(thr, 0, &len);
DUK_UNREF(str);
- duk_push_size_t(ctx, len);
+ duk_push_size_t(thr, len);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -26846,10 +27940,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) {
duk_hobject *h_arg;
- duk_int_t total_length = 0;
+ duk_uint_t total_length;
duk_hbufobj *h_bufobj;
duk_hbufobj *h_bufres;
duk_hbuffer *h_val;
@@ -26858,63 +27951,66 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
duk_size_t space_left;
duk_size_t copy_size;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
/* Node.js accepts only actual Arrays. */
- h_arg = duk_require_hobject(ctx, 0);
+ h_arg = duk_require_hobject(thr, 0);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* Compute result length and validate argument buffers. */
- n = (duk_uint_t) duk_get_length(ctx, 0);
+ n = (duk_uint_t) duk_get_length(thr, 0);
+ total_length = 0;
for (i = 0; i < n; i++) {
/* Neutered checks not necessary here: neutered buffers have
* zero 'length' so we'll effectively skip them.
*/
- DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
- h_bufobj = duk__require_bufobj_value(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2); /* [ array totalLength ] */
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
+ h_bufobj = duk__require_bufobj_value(thr, 2);
DUK_ASSERT(h_bufobj != NULL);
total_length += h_bufobj->length;
- duk_pop(ctx);
+ if (DUK_UNLIKELY(total_length < h_bufobj->length)) {
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr); /* Wrapped. */
+ }
+ duk_pop(thr);
}
/* In Node.js v0.12.1 a 1-element array is special and won't create a
* copy, this was fixed later so an explicit check no longer needed.
*/
/* User totalLength overrides a computed length, but we'll check
- * every copy in the copy loop. Note that duk_to_uint() can
+ * every copy in the copy loop. Note that duk_to_int() can
* technically have arbitrary side effects so we need to recheck
* the buffers in the copy loop.
*/
- if (!duk_is_undefined(ctx, 1) && n > 0) {
+ if (!duk_is_undefined(thr, 1) && n > 0) {
/* For n == 0, Node.js ignores totalLength argument and
* returns a zero length buffer.
*/
- total_length = duk_to_int(ctx, 1);
- }
- if (total_length < 0) {
- DUK_DCERROR_RANGE_INVALID_ARGS(thr);
+ duk_int_t total_length_signed;
+ total_length_signed = duk_to_int(thr, 1);
+ if (total_length_signed < 0) {
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
+ }
+ total_length = (duk_uint_t) total_length_signed;
}
- h_bufres = duk_push_bufobj_raw(ctx,
+ h_bufres = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
DUK_ASSERT(h_bufres != NULL);
- p = (duk_uint8_t *) duk_push_fixed_buffer_zero(ctx, total_length); /* must be zeroed, all bytes not necessarily written over */
+ p = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, total_length); /* must be zeroed, all bytes not necessarily written over */
DUK_ASSERT(p != NULL);
- space_left = total_length;
+ space_left = (duk_size_t) total_length;
for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */
+ DUK_ASSERT_TOP(thr, 4); /* [ array totalLength bufres buf ] */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- h_bufobj = duk__require_bufobj_value(ctx, 4);
+ duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
+ h_bufobj = duk__require_bufobj_value(thr, 4);
DUK_ASSERT(h_bufobj != NULL);
copy_size = h_bufobj->length;
@@ -26934,16 +28030,16 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
p += copy_size;
space_left -= copy_size;
- duk_pop(ctx);
+ duk_pop(thr);
}
- h_val = duk_known_hbuffer(ctx, -1);
+ h_val = duk_known_hbuffer(thr, -1);
- duk__set_bufobj_buffer(ctx, h_bufres, h_val);
+ duk__set_bufobj_buffer(thr, h_bufres, h_val);
h_bufres->is_typedarray = 1;
DUK_ASSERT_HBUFOBJ_VALID(h_bufres);
- duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */
+ duk_pop(thr); /* pop plain buffer, now reachable through h_bufres */
return 1; /* return h_bufres */
}
@@ -26974,9 +28070,8 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
#define DUK__FLD_TYPEDARRAY (1 << 5)
/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
+ duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
duk_small_int_t magic_ftype;
duk_small_int_t magic_bigendian;
duk_small_int_t magic_signed;
@@ -26991,15 +28086,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
duk_uint8_t *buf;
duk_double_union du;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
magic_ftype = magic & 0x0007;
magic_bigendian = magic & 0x0008;
magic_signed = magic & 0x0010;
magic_typedarray = magic & 0x0020;
- h_this = duk__require_bufobj_this(ctx); /* XXX: very inefficient for plain buffers */
+ h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
DUK_ASSERT(h_this != NULL);
buffer_length = h_this->length;
@@ -27011,12 +28103,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (magic_typedarray) {
no_assert = 0;
#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */
+ endswap = !duk_to_boolean(thr, 1); /* 1=little endian */
#else
- endswap = duk_to_boolean(ctx, 1); /* 1=little endian */
+ endswap = duk_to_boolean(thr, 1); /* 1=little endian */
#endif
} else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
+ no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
#if defined(DUK_USE_INTEGER_LE)
endswap = magic_bigendian;
#else
@@ -27028,7 +28120,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
* This ensures we can add a small byte length (1-8) to the offset in
* bound checks and not wrap.
*/
- offset_signed = duk_to_int(ctx, 0);
+ offset_signed = duk_to_int(thr, 0);
offset = (duk_uint_t) offset_signed;
if (offset_signed < 0) {
goto fail_bounds;
@@ -27069,9 +28161,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
}
tmp = buf[offset];
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int8_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -27086,9 +28178,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP16(tmp);
}
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int16_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -27103,9 +28195,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP32(tmp);
}
if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp));
+ duk_push_int(thr, (duk_int_t) ((duk_int32_t) tmp));
} else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
+ duk_push_uint(thr, (duk_uint_t) tmp);
}
break;
}
@@ -27120,7 +28212,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = DUK_BSWAP32(tmp);
du.ui[0] = tmp;
}
- duk_push_number(ctx, (duk_double_t) du.f[0]);
+ duk_push_number(thr, (duk_double_t) du.f[0]);
break;
}
case DUK__FLD_DOUBLE: {
@@ -27131,7 +28223,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (endswap) {
DUK_DBLUNION_BSWAP64(&du);
}
- duk_push_number(ctx, (duk_double_t) du.d);
+ duk_push_number(thr, (duk_double_t) du.d);
break;
}
case DUK__FLD_VARINT: {
@@ -27149,7 +28241,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
#endif
const duk_uint8_t *p;
- field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */
+ field_bytelen = duk_get_int(thr, 1); /* avoid side effects! */
if (field_bytelen < 1 || field_bytelen > 6) {
goto fail_field_length;
}
@@ -27185,11 +28277,11 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
if (magic_signed) {
/* Shift to sign extend. */
- shift_tmp = 64 - (field_bytelen * 8);
+ shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U);
tmp = (tmp << shift_tmp) >> shift_tmp;
}
- duk_push_i64(ctx, tmp);
+ duk_push_i64(thr, tmp);
#else
highbyte = p[i];
if (magic_signed && (highbyte & 0x80) != 0) {
@@ -27207,7 +28299,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
tmp = (tmp * 256.0) + (duk_double_t) p[i];
}
- duk_push_number(ctx, tmp);
+ duk_push_number(thr, tmp);
#endif
break;
}
@@ -27225,7 +28317,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
/* Node.js return value for noAssert out-of-bounds reads is
* usually (but not always) NaN. Return NaN consistently.
*/
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
DUK_DCERROR_RANGE_INVALID_ARGS(thr);
@@ -27234,9 +28326,8 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
+ duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
duk_small_int_t magic_ftype;
duk_small_int_t magic_bigendian;
duk_small_int_t magic_signed;
@@ -27252,16 +28343,13 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
duk_double_union du;
duk_int_t nbytes = 0;
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
magic_ftype = magic & 0x0007;
magic_bigendian = magic & 0x0008;
magic_signed = magic & 0x0010;
magic_typedarray = magic & 0x0020;
DUK_UNREF(magic_signed);
- h_this = duk__require_bufobj_this(ctx); /* XXX: very inefficient for plain buffers */
+ h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
DUK_ASSERT(h_this != NULL);
buffer_length = h_this->length;
@@ -27273,13 +28361,13 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (magic_typedarray) {
no_assert = 0;
#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */
+ endswap = !duk_to_boolean(thr, 2); /* 1=little endian */
#else
- endswap = duk_to_boolean(ctx, 2); /* 1=little endian */
+ endswap = duk_to_boolean(thr, 2); /* 1=little endian */
#endif
- duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */
+ duk_swap(thr, 0, 1); /* offset/value order different from Node.js */
} else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
+ no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
#if defined(DUK_USE_INTEGER_LE)
endswap = magic_bigendian;
#else
@@ -27291,7 +28379,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
* This ensures we can add a small byte length (1-8) to the offset in
* bound checks and not wrap.
*/
- offset_signed = duk_to_int(ctx, 1);
+ offset_signed = duk_to_int(thr, 1);
offset = (duk_uint_t) offset_signed;
/* We need 'nbytes' even for a failed offset; return value must be
@@ -27301,7 +28389,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
} else {
- nbytes = duk_get_int(ctx, 2);
+ nbytes = duk_get_int(thr, 2);
if (nbytes < 1 || nbytes > 6) {
goto fail_field_length;
}
@@ -27316,7 +28404,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
"magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
"endswap=%d",
- duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert,
+ duk_get_tval(thr, 0), (long) buffer_length, (long) offset, (int) no_assert,
(unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
(int) (magic_signed >> 4), (int) endswap));
@@ -27324,7 +28412,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
* the field type specific coercion below can't have side effects
* that would invalidate check_length.
*/
- duk_to_number(ctx, 0);
+ duk_to_number(thr, 0);
/* Update 'buffer_length' to be the effective, safe limit which
* takes into account the underlying buffer. This value will be
@@ -27352,7 +28440,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
goto fail_bounds;
}
/* sign doesn't matter when writing */
- buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0);
+ buf[offset] = (duk_uint8_t) duk_to_uint32(thr, 0);
break;
}
case DUK__FLD_16BIT: {
@@ -27360,7 +28448,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 2U > check_length) {
goto fail_bounds;
}
- tmp = (duk_uint16_t) duk_to_uint32(ctx, 0);
+ tmp = (duk_uint16_t) duk_to_uint32(thr, 0);
if (endswap) {
tmp = DUK_BSWAP16(tmp);
}
@@ -27374,7 +28462,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- tmp = (duk_uint32_t) duk_to_uint32(ctx, 0);
+ tmp = (duk_uint32_t) duk_to_uint32(thr, 0);
if (endswap) {
tmp = DUK_BSWAP32(tmp);
}
@@ -27388,7 +28476,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- du.f[0] = (duk_float_t) duk_to_number(ctx, 0);
+ du.f[0] = (duk_float_t) duk_to_number(thr, 0);
if (endswap) {
tmp = du.ui[0];
tmp = DUK_BSWAP32(tmp);
@@ -27402,7 +28490,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (offset + 8U > check_length) {
goto fail_bounds;
}
- du.d = (duk_double_t) duk_to_number(ctx, 0);
+ du.d = (duk_double_t) duk_to_number(thr, 0);
if (endswap) {
DUK_DBLUNION_BSWAP64(&du);
}
@@ -27452,7 +28540,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*/
#if defined(DUK_USE_64BIT_OPS)
- tmp = (duk_int64_t) duk_to_number(ctx, 0);
+ tmp = (duk_int64_t) duk_to_number(thr, 0);
p = (duk_uint8_t *) (buf + offset);
do {
i += i_step;
@@ -27461,7 +28549,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
tmp = tmp >> 8; /* unnecessary shift for last byte */
} while (i != i_end);
#else
- tmp = duk_to_number(ctx, 0);
+ tmp = duk_to_number(thr, 0);
p = (duk_uint8_t *) (buf + offset);
do {
i += i_step;
@@ -27487,7 +28575,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*/
return 0;
}
- duk_push_uint(ctx, offset + nbytes);
+ duk_push_uint(thr, offset + (duk_uint_t) nbytes);
return 1;
fail_neutered:
@@ -27503,7 +28591,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
if (magic_typedarray) {
return 0;
}
- duk_push_uint(ctx, offset + nbytes);
+ duk_push_uint(thr, offset + (duk_uint_t) nbytes);
return 1;
}
DUK_DCERROR_RANGE_INVALID_ARGS(thr);
@@ -27515,10 +28603,10 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_context *ctx, duk_hbuffer *h_buf) {
+DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_hthread *thr, duk_hbuffer *h_buf) {
duk_hbufobj *h_res;
- h_res = duk_push_bufobj_raw(ctx,
+ h_res = duk_push_bufobj_raw(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_BUFOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
@@ -27526,20 +28614,20 @@ DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_context *ctx, duk_hbuffer
DUK_ASSERT(h_res != NULL);
DUK_UNREF(h_res);
- duk__set_bufobj_buffer(ctx, h_res, h_buf);
+ duk__set_bufobj_buffer(thr, h_res, h_buf);
DUK_ASSERT_HBUFOBJ_VALID(h_res);
DUK_ASSERT(h_res->buf_prop == NULL);
return h_res;
}
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
duk_hbufobj *h_bufobj;
- h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
DUK_ASSERT(h_bufobj != NULL);
if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer"));
- (void) duk__autospawn_arraybuffer(ctx, (duk_hbuffer *) h_bufobj);
+ (void) duk__autospawn_arraybuffer(thr, (duk_hbuffer *) h_bufobj);
return 1;
} else {
if (h_bufobj->buf_prop == NULL &&
@@ -27548,7 +28636,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) {
duk_hbufobj *h_arrbuf;
DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView"));
- h_arrbuf = duk__autospawn_arraybuffer(ctx, h_bufobj->buf);
+ h_arrbuf = duk__autospawn_arraybuffer(thr, h_bufobj->buf);
if (h_bufobj->buf_prop == NULL) {
/* Must recheck buf_prop, in case ArrayBuffer
@@ -27573,68 +28661,68 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) {
/* Left on stack; pushed for the second time below (OK). */
}
if (h_bufobj->buf_prop) {
- duk_push_hobject(ctx, h_bufobj->buf_prop);
+ duk_push_hobject(thr, h_bufobj->buf_prop);
return 1;
}
}
return 0;
}
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
duk_hbufobj *h_bufobj;
- h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
DUK_ASSERT(h_bufobj != NULL);
if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
- duk_push_uint(ctx, 0);
+ duk_push_uint(thr, 0);
} else {
/* If neutered must return 0; offset is zeroed during
* neutering.
*/
- duk_push_uint(ctx, h_bufobj->offset);
+ duk_push_uint(thr, h_bufobj->offset);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
duk_hbufobj *h_bufobj;
- h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/);
+ h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
DUK_ASSERT(h_bufobj != NULL);
if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
duk_hbuffer *h_buf;
h_buf = (duk_hbuffer *) h_bufobj;
DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */
- duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
+ duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
} else {
/* If neutered must return 0; length is zeroed during
* neutering.
*/
- duk_push_uint(ctx, h_bufobj->length);
+ duk_push_uint(thr, h_bufobj->length);
}
return 1;
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* No .buffer getter without ArrayBuffer support. */
#if 0
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
return 0;
}
#endif
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx) {
- duk_push_uint(ctx, 0);
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
+ duk_push_uint(thr, 0);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
duk_hbuffer *h_buf;
/* XXX: helper? */
- duk_push_this(ctx);
- h_buf = duk_require_hbuffer(ctx, -1);
- duk_push_uint(ctx, DUK_HBUFFER_GET_SIZE(h_buf));
+ duk_push_this(thr);
+ h_buf = duk_require_hbuffer(thr, -1);
+ duk_push_uint(thr, DUK_HBUFFER_GET_SIZE(h_buf));
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -27672,10 +28760,10 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx) {
* Forward declarations
*/
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val);
-DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags);
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset);
+DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags);
+DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val);
+DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags);
/*
* Other file level defines
@@ -27839,7 +28927,7 @@ DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
*/
};
-DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
+DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const char *str) {
duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
@@ -27887,7 +28975,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
}
} else {
duk_uint_fast32_t match_val;
- duk_small_int_t sep_idx;
+ duk_small_uint_t sep_idx;
if (ndigits <= 0) {
goto reject;
@@ -28011,7 +29099,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
}
d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
@@ -28034,7 +29122,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const ch
* UTC and '2012/01/01' as local time.
*/
-DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
+DUK_LOCAL duk_ret_t duk__parse_string(duk_hthread *thr, const char *str) {
/* XXX: there is a small risk here: because the ISO 8601 parser is
* very loose, it may end up parsing some datetime values which
* would be better parsed with a platform specific parser.
@@ -28043,7 +29131,7 @@ DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
DUK_ASSERT(str != NULL);
DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
- if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
+ if (duk__parse_string_iso8601_subset(thr, str) != 0) {
return 1;
}
@@ -28053,14 +29141,14 @@ DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
* - Don't push anything on stack and return 0
*/
- if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
+ if (DUK_USE_DATE_PARSE_STRING(thr, str) != 0) {
return 1;
}
#else
/* No platform-specific parsing, this is not an error. */
#endif
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
@@ -28253,9 +29341,9 @@ DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_
return (duk_double_t) day_num + day;
}
-/* Split time value into parts. The time value is assumed to be an internal
- * one, i.e. finite, no fractions. Possible local time adjustment has already
- * been applied when reading the time value.
+/* Split time value into parts. The time value may contain fractions (it may
+ * come from duk_time_to_components() API call) which are truncated. Possible
+ * local time adjustment has already been applied when reading the time value.
*/
DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags) {
duk_double_t d1, d2;
@@ -28274,7 +29362,8 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
duk_small_int_t arridx;
DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
+ d = DUK_FLOOR(d); /* remove fractions if present */
+ DUK_ASSERT(DUK_FLOOR(d) == d);
/* The timevalue must be in valid Ecmascript range, but since a local
* time offset can be applied, we need to allow a +/- 24h leeway to
@@ -28284,7 +29373,7 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
- /* these computations are guaranteed to be exact for the valid
+ /* These computations are guaranteed to be exact for the valid
* E5 time value range, assuming milliseconds without fractions.
*/
d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
@@ -28540,21 +29629,20 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dpar
* internal time value. At the end, stack is: [ ... this timeval ].
* Returns the time value. Local time adjustment is done if requested.
*/
-DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
duk_hobject *h;
duk_double_t d;
duk_int_t tzoffset = 0;
- duk_push_this(ctx);
- h = duk_get_hobject(ctx, -1); /* XXX: getter with class check, useful in built-ins */
+ duk_push_this(thr);
+ h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */
if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
DUK_ERROR_TYPE(thr, "expected Date");
}
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
- d = duk_to_number_m1(ctx);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ d = duk_to_number_m1(thr);
+ duk_pop(thr);
if (DUK_ISNAN(d)) {
if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
@@ -28582,23 +29670,23 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk
return d;
}
-DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags) {
- return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
+DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags) {
+ return duk__push_this_get_timeval_tzoffset(thr, flags, NULL);
}
/* Set timeval to 'this' from dparts, push the new time value onto the
* value stack and return 1 (caller can then tail call us). Expects
* the value stack to contain 'this' on the stack top.
*/
-DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags) {
+DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags) {
duk_double_t d;
/* [ ... this ] */
d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
- duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */
- duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */
- duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE);
+ duk_push_number(thr, d); /* -> [ ... this timeval_new ] */
+ duk_dup_top(thr); /* -> [ ... this timeval_new timeval_new ] */
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE);
/* stack top: new time value, return 1 to allow tail calls */
return 1;
@@ -28628,13 +29716,23 @@ DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, d
/* tzoffset seconds are dropped; 16 bits suffice for
* time offset in minutes
*/
+ const char *fmt;
+ duk_small_int_t tmp, arg_hours, arg_minutes;
+
if (tzoffset >= 0) {
- duk_small_int_t tmp = tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
+ tmp = tzoffset;
+ fmt = "+%02d:%02d";
} else {
- duk_small_int_t tmp = -tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
+ tmp = -tzoffset;
+ fmt = "-%02d:%02d";
}
+ tmp = tmp / 60;
+ arg_hours = tmp / 60;
+ arg_minutes = tmp % 60;
+ DUK_ASSERT(arg_hours <= 24); /* Even less is actually guaranteed for a valid tzoffset. */
+ arg_hours = arg_hours & 0x3f; /* For [0,24] this is a no-op, but fixes GCC 7 warning, see https://github.com/svaarala/duktape/issues/1602. */
+
+ DUK_SNPRINTF(tzstr, sizeof(tzstr), fmt, (int) arg_hours, (int) arg_minutes);
tzstr[sizeof(tzstr) - 1] = (char) 0;
} else {
tzstr[0] = DUK_ASC_UC_Z;
@@ -28665,7 +29763,7 @@ DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, d
* internal time value, and format date and/or time in a few formats.
* Return value allows tail calls.
*/
-DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t flags) {
+DUK_LOCAL duk_ret_t duk__to_string_helper(duk_hthread *thr, duk_small_uint_t flags) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
@@ -28674,9 +29772,9 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
DUK_UNREF(rc); /* unreferenced with some options */
- d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
+ d = duk__push_this_get_timeval_tzoffset(thr, flags, &tzoffset);
if (DUK_ISNAN(d)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INVALID_DATE);
return 1;
}
DUK_ASSERT(DUK_ISFINITE(d));
@@ -28697,7 +29795,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* - Don't push anything and return 0
*/
- rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
+ rc = DUK_USE_DATE_FORMAT_STRING(thr, parts, tzoffset, flags);
if (rc != 0) {
return 1;
}
@@ -28712,7 +29810,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* is shared.
*/
duk__format_parts_iso8601(parts, tzoffset, flags, buf);
- duk_push_string(ctx, (const char *) buf);
+ duk_push_string(thr, (const char *) buf);
return 1;
}
@@ -28721,7 +29819,7 @@ DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t fla
* local time), push a specified component as a return value to the
* value stack and return 1 (caller can then tail call us).
*/
-DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flags_and_idx) {
+DUK_LOCAL duk_ret_t duk__get_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_idx) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
@@ -28729,9 +29827,9 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
- d = duk__push_this_get_timeval(ctx, flags_and_idx);
+ d = duk__push_this_get_timeval(thr, flags_and_idx);
if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
DUK_ASSERT(DUK_ISFINITE(d));
@@ -28742,7 +29840,7 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
* only in certain cases. The legacy getYear() getter applies -1900
* unconditionally.
*/
- duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
+ duk_push_int(thr, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
return 1;
}
@@ -28753,7 +29851,7 @@ DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flag
* new time value as a return value to the value stack and return 1
* (caller can then tail call us).
*/
-DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flags_and_maxnargs) {
+DUK_LOCAL duk_ret_t duk__set_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_maxnargs) {
duk_double_t d;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
@@ -28762,8 +29860,8 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
duk_small_uint_t idx_first, idx;
duk_small_uint_t i;
- nargs = duk_get_top(ctx);
- d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
+ nargs = duk_get_top(thr);
+ d = duk__push_this_get_timeval(thr, flags_and_maxnargs);
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
if (DUK_ISFINITE(d)) {
@@ -28818,10 +29916,10 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
- duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
+ duk__twodigit_year_fixup(thr, (duk_idx_t) i);
}
- dparts[idx] = duk_to_number(ctx, i);
+ dparts[idx] = duk_to_number(thr, (duk_idx_t) i);
if (idx == DUK_DATE_IDX_DAY) {
/* Day-of-month is one-based in the API, but zero-based
@@ -28841,10 +29939,10 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
* for part setters.
*/
if (DUK_ISFINITE(d)) {
- return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
+ return duk__set_this_timeval_from_dparts(thr, dparts, flags_and_maxnargs);
} else {
/* Internal timevalue is already NaN, so don't touch it. */
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
}
@@ -28852,7 +29950,7 @@ DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flag
/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
* 1900 and replace value at idx_val.
*/
-DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
+DUK_LOCAL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val) {
duk_double_t d;
/* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
@@ -28860,25 +29958,25 @@ DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
*/
/* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
- duk_to_number(ctx, idx_val);
- if (duk_is_nan(ctx, idx_val)) {
+ duk_to_number(thr, idx_val);
+ if (duk_is_nan(thr, idx_val)) {
return;
}
- duk_dup(ctx, idx_val);
- duk_to_int(ctx, -1);
- d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */
+ duk_dup(thr, idx_val);
+ duk_to_int(thr, -1);
+ d = duk_get_number(thr, -1); /* get as double to handle huge numbers correctly */
if (d >= 0.0 && d <= 99.0) {
d += 1900.0;
- duk_push_number(ctx, d);
- duk_replace(ctx, idx_val);
+ duk_push_number(thr, d);
+ duk_replace(thr, idx_val);
}
- duk_pop(ctx);
+ duk_pop(thr);
}
/* Set datetime parts from stack arguments, defaulting any missing values.
* Day-of-week is not set; it is not required when setting the time value.
*/
-DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, duk_idx_t nargs) {
+DUK_LOCAL void duk__set_parts_from_args(duk_hthread *thr, duk_double_t *dparts, duk_idx_t nargs) {
duk_double_t d;
duk_small_uint_t i;
duk_small_uint_t idx;
@@ -28886,7 +29984,7 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
/* Causes a ToNumber() coercion, but doesn't break coercion order since
* year is coerced first anyway.
*/
- duk__twodigit_year_fixup(ctx, 0);
+ duk__twodigit_year_fixup(thr, 0);
/* There are at most 7 args, but we use 8 here so that also
* DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
@@ -28896,7 +29994,7 @@ DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts,
/* Note: rely on index ordering */
idx = DUK_DATE_IDX_YEAR + i;
if ((duk_idx_t) i < nargs) {
- d = duk_to_number(ctx, (duk_idx_t) i);
+ d = duk_to_number(thr, (duk_idx_t) i);
if (idx == DUK_DATE_IDX_DAY) {
/* Convert day from one-based to zero-based (internal). This may
* cause the day part to be negative, which is OK.
@@ -29053,9 +30151,9 @@ static duk_uint16_t duk__date_magics[] = {
DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
};
-DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
- duk_small_int_t magicidx = (duk_small_uint_t) duk_get_current_magic(ctx);
- DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
+DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_hthread *thr) {
+ duk_small_uint_t magicidx = (duk_small_uint_t) duk_get_current_magic(thr);
+ DUK_ASSERT(magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
return (duk_small_uint_t) duk__date_magics[magicidx];
}
@@ -29064,15 +30162,15 @@ DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
* Constructor calls
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
- duk_bool_t is_cons = duk_is_constructor_call(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) {
+ duk_idx_t nargs = duk_get_top(thr);
+ duk_bool_t is_cons = duk_is_constructor_call(thr);
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
- (void) duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
@@ -29083,43 +30181,43 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
*/
if (nargs == 0 || !is_cons) {
- d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
+ d = duk__timeclip(duk_time_get_ecmascript_time_nofrac(thr));
+ duk_push_number(thr, d);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
if (!is_cons) {
/* called as a normal function: return new Date().toString() */
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
} else if (nargs == 1) {
const char *str;
- duk_to_primitive(ctx, 0, DUK_HINT_NONE);
- str = duk_get_string_notsymbol(ctx, 0);
+ duk_to_primitive(thr, 0, DUK_HINT_NONE);
+ str = duk_get_string_notsymbol(thr, 0);
if (str) {
- duk__parse_string(ctx, str);
- duk_replace(ctx, 0); /* may be NaN */
+ duk__parse_string(thr, str);
+ duk_replace(thr, 0); /* may be NaN */
}
- d = duk__timeclip(duk_to_number(ctx, 0)); /* symbols fail here */
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
+ d = duk__timeclip(duk_to_number(thr, 0)); /* symbols fail here */
+ duk_push_number(thr, d);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
return 1;
}
- duk__set_parts_from_args(ctx, dparts, nargs);
+ duk__set_parts_from_args(thr, dparts, nargs);
/* Parts are in local time, convert when setting. */
- (void) duk__set_this_timeval_from_dparts(ctx, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
- duk_pop(ctx); /* -> [ ... this ] */
+ (void) duk__set_this_timeval_from_dparts(thr, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
+ duk_pop(thr); /* -> [ ... this ] */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
- return duk__parse_string(ctx, duk_to_string(ctx, 0));
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_hthread *thr) {
+ return duk__parse_string(thr, duk_to_string(thr, 0));
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) {
+ duk_idx_t nargs = duk_get_top(thr);
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t d;
@@ -29128,21 +30226,21 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
*/
if (nargs < 2) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else {
- duk__set_parts_from_args(ctx, dparts, nargs);
+ duk__set_parts_from_args(thr, dparts, nargs);
d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) {
duk_double_t d;
- d = DUK_USE_DATE_GET_NOW(ctx);
+ d = duk_time_get_ecmascript_time_nofrac(thr);
DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
@@ -29180,44 +30278,44 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
* toISOString() requires a RangeError for invalid date values.
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
- duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
- return duk__to_string_helper(ctx, flags);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_hthread *thr) {
+ duk_small_uint_t flags = duk__date_get_indirect_magic(thr);
+ return duk__to_string_helper(thr, flags);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_hthread *thr) {
/* This native function is also used for Date.prototype.getTime()
* as their behavior is identical.
*/
- duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ this ] */
+ duk_double_t d = duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ this ] */
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_hthread *thr) {
/* Note: toJSON() is a generic function which works even if 'this'
* is not a Date. The sole argument is ignored.
*/
- duk_push_this(ctx);
- duk_to_object(ctx, -1);
+ duk_push_this(thr);
+ duk_to_object(thr, -1);
- duk_dup_top(ctx);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- if (duk_is_number(ctx, -1)) {
- duk_double_t d = duk_get_number(ctx, -1);
+ duk_dup_top(thr);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
+ if (duk_is_number(thr, -1)) {
+ duk_double_t d = duk_get_number(thr, -1);
if (!DUK_ISFINITE(d)) {
- duk_push_null(ctx);
+ duk_push_null(thr);
return 1;
}
}
- duk_pop(ctx);
+ duk_pop(thr);
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
- duk_dup_m2(ctx); /* -> [ O toIsoString O ] */
- duk_call_method(ctx, 0);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_ISO_STRING);
+ duk_dup_m2(thr); /* -> [ O toIsoString O ] */
+ duk_call_method(thr, 0);
return 1;
}
@@ -29262,12 +30360,12 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
* function (duk_bi_date_prototype_value_of).
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
- return duk__get_part_helper(ctx, flags_and_idx);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_hthread *thr) {
+ duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(thr);
+ return duk__get_part_helper(thr, flags_and_idx);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_hthread *thr) {
/*
* Return (t - LocalTime(t)) in minutes:
*
@@ -29286,14 +30384,14 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ct
duk_int_t tzoffset;
/* Note: DST adjustment is determined using UTC time. */
- d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
+ d = duk__push_this_get_timeval(thr, 0 /*flags*/);
DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else {
DUK_ASSERT(DUK_ISFINITE(d));
tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
- duk_push_int(ctx, -tzoffset / 60);
+ duk_push_int(thr, -tzoffset / 60);
}
return 1;
}
@@ -29347,19 +30445,19 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ct
* the year will be set regardless of actual argument count.
*/
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
- return duk__set_part_helper(ctx, flags_and_maxnargs);
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_hthread *thr) {
+ duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(thr);
+ return duk__set_part_helper(thr, flags_and_maxnargs);
}
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) {
duk_double_t d;
- (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
- d = duk__timeclip(duk_to_number(ctx, 0));
- duk_push_number(ctx, d);
- duk_dup_top(ctx);
- duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
+ (void) duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ timeval this ] */
+ d = duk__timeclip(duk_to_number(thr, 0));
+ duk_push_number(thr, d);
+ duk_dup_top(thr);
+ duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
return 1;
}
@@ -29432,18 +30530,18 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) {
struct timeval tv;
duk_double_t d;
if (gettimeofday(&tv, NULL) != 0) {
- DUK_ERROR_INTERNAL(thr);
+ DUK_D(DUK_DPRINT("gettimeofday() failed"));
+ return 0.0;
}
+ /* As of Duktape 2.2.0 allow fractions. */
d = ((duk_double_t) tv.tv_sec) * 1000.0 +
- ((duk_double_t) (tv.tv_usec / 1000));
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions */
+ ((duk_double_t) tv.tv_usec) / 1000.0;
return d;
}
@@ -29451,11 +30549,14 @@ 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) {
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) {
time_t t;
- DUK_UNREF(ctx);
t = time(NULL);
+ if (t == (time_t) -1) {
+ DUK_D(DUK_DPRINT("time() failed"));
+ return 0.0;
+ }
return ((duk_double_t) t) * 1000.0;
}
#endif /* DUK_USE_DATE_NOW_TIME */
@@ -29611,12 +30712,12 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
#endif /* DUK_USE_DATE_TZO_GMTIME */
#if defined(DUK_USE_DATE_PRS_STRPTIME)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str) {
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) {
struct tm tm;
time_t t;
char buf[DUK__STRPTIME_BUF_SIZE];
- /* copy to buffer with spare to avoid Valgrind gripes from strptime */
+ /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */
DUK_ASSERT(str != NULL);
DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
@@ -29636,7 +30737,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, cons
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
- duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
+ duk_push_number(thr, ((duk_double_t) t) * 1000.0);
return 1;
}
}
@@ -29646,7 +30747,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, cons
#endif /* DUK_USE_DATE_PRS_STRPTIME */
#if defined(DUK_USE_DATE_PRS_GETDATE)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str) {
+DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) {
struct tm tm;
duk_small_int_t rc;
time_t t;
@@ -29663,7 +30764,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
- duk_push_number(ctx, (duk_double_t) t);
+ duk_push_number(thr, (duk_double_t) t);
return 1;
}
}
@@ -29673,7 +30774,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const
#endif /* DUK_USE_DATE_PRS_GETDATE */
#if defined(DUK_USE_DATE_FMT_STRFTIME)
-DUK_INTERNAL 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) {
+DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
char buf[DUK__STRFTIME_BUF_SIZE];
struct tm tm;
const char *fmt;
@@ -29719,11 +30820,24 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_
(void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
- duk_push_string(ctx, buf);
+ duk_push_string(thr, buf);
return 1;
}
#endif /* DUK_USE_DATE_FMT_STRFTIME */
+#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
+DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) {
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0;
+ } else {
+ DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed"));
+ return 0.0;
+ }
+}
+#endif
+
/* automatic undefs */
#undef DUK__STRFTIME_BUF_SIZE
#undef DUK__STRPTIME_BUF_SIZE
@@ -29751,6 +30865,12 @@ DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEG
res->HighPart = ft.dwHighDateTime;
}
}
+
+DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
+ res->LowPart = ft->dwLowDateTime;
+ res->HighPart = ft->dwHighDateTime;
+}
+
DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
DUK_MEMZERO((void *) st, sizeof(*st));
st->wYear = 1970;
@@ -29765,29 +30885,51 @@ DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
#if defined(DUK_USE_DATE_NOW_WINDOWS)
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) {
/* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
*/
SYSTEMTIME st1, st2;
ULARGE_INTEGER tmp1, tmp2;
- DUK_UNREF(ctx);
-
GetSystemTime(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
duk__set_systime_jan1970(&st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
- /* Difference is in 100ns units, convert to milliseconds w/o fractions */
- return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
+ /* Difference is in 100ns units, convert to milliseconds, keeping
+ * fractions since Duktape 2.2.0. This is only theoretical because
+ * SYSTEMTIME is limited to milliseconds.
+ */
+ return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
+DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) {
+ /* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime()
+ * for more accuracy.
+ */
+ FILETIME ft1;
+ SYSTEMTIME st2;
+ ULARGE_INTEGER tmp1, tmp2;
+
+ GetSystemTimePreciseAsFileTime(&ft1);
+ duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1);
+
+ duk__set_systime_jan1970(&st2);
+ duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
+
+ /* Difference is in 100ns units, convert to milliseconds, keeping
+ * fractions since Duktape 2.2.0.
+ */
+ return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
+}
+#endif /* DUK_USE_DATE_NOW_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS)
-DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
+DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
SYSTEMTIME st3;
@@ -29822,12 +30964,12 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
/* Positive if local time ahead of UTC. */
- return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */
+ return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
-DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
+DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
FILETIME ft1;
@@ -29854,9 +30996,34 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_do
FileTimeToSystemTime((const FILETIME *) &ft2, &st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
- return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / 10000000LL); /* seconds */
+ return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */
+
+#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
+DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
+ LARGE_INTEGER count, freq;
+
+ /* There are legacy issues with QueryPerformanceCounter():
+ * - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward
+ * - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
+ *
+ * We avoid these by enabling QPC by default only for Vista or later.
+ */
+
+ if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) {
+ /* XXX: QueryPerformanceFrequency() can be cached */
+ return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0;
+ } else {
+ /* MSDN: "On systems that run Windows XP or later, the function
+ * will always succeed and will thus never return zero."
+ * Provide minimal error path just in case user enables this
+ * feature in pre-XP Windows.
+ */
+ return 0.0;
+ }
+}
+#endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */
/*
* Duktape built-ins
*
@@ -29872,37 +31039,36 @@ DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_do
#if defined(DUK_USE_DUKTAPE_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
- duk_inspect_value(ctx, -1);
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) {
+ duk_inspect_value(thr, -1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) {
duk_int_t level;
- level = duk_to_int(ctx, 0);
- duk_inspect_callstack_entry(ctx, level);
+ level = duk_to_int(thr, 0);
+ duk_inspect_callstack_entry(thr, level);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) {
duk_small_uint_t flags;
- flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
+ flags = (duk_small_uint_t) duk_get_uint(thr, 0);
duk_heap_mark_and_sweep(thr->heap, flags);
/* XXX: Not sure what the best return value would be in the API.
* Return true for now.
*/
- duk_push_true(ctx);
+ duk_push_true(thr);
return 1;
}
#if defined(DUK_USE_FINALIZER_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
- (void) duk_require_hobject(ctx, 0);
- if (duk_get_top(ctx) >= 2) {
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) {
+ (void) duk_require_hobject(thr, 0);
+ if (duk_get_top(thr) >= 2) {
/* Set: currently a finalizer is disabled by setting it to
* undefined; this does not remove the property at the moment.
* The value could be type checked to be either a function
@@ -29910,43 +31076,40 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
* be deleted. Must use duk_set_finalizer() to keep
* DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync.
*/
- duk_set_top(ctx, 2);
- duk_set_finalizer(ctx, 0);
+ duk_set_top(thr, 2);
+ duk_set_finalizer(thr, 0);
return 0;
} else {
/* Get. */
- DUK_ASSERT(duk_get_top(ctx) == 1);
- duk_get_finalizer(ctx, 0);
+ DUK_ASSERT(duk_get_top(thr) == 1);
+ duk_get_finalizer(thr, 0);
return 1;
}
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) {
duk_hstring *h_str;
- DUK_UNREF(thr);
-
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
- h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons. */
- duk_require_valid_index(ctx, 1);
+ h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons. */
+ duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_hex_encode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_base64_encode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_stringify_helper(ctx,
+ duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
@@ -29956,7 +31119,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
#endif
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_stringify_helper(ctx,
+ duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
@@ -29969,38 +31132,35 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) {
duk_hstring *h_str;
- DUK_UNREF(thr);
-
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
- h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons */
- duk_require_valid_index(ctx, 1);
+ h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons */
+ duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_hex_decode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
+ duk_set_top(thr, 2);
+ duk_base64_decode(thr, 1);
+ DUK_ASSERT_TOP(thr, 2);
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_parse_helper(ctx,
+ duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
#endif
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_parse_helper(ctx,
+ duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
@@ -30015,9 +31175,9 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
* Compact an object
*/
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 1);
- duk_compact(ctx, 0);
+DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 1);
+ duk_compact(thr, 0);
return 1; /* return the argument object */
}
@@ -30201,7 +31361,7 @@ DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
} else {
/* low surrogate */
if (enc_ctx->lead != 0x0000L) {
- codepoint = 0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L);
+ codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L));
enc_ctx->lead = 0x0000L;
} else {
/* unpaired low surrogate */
@@ -30220,14 +31380,14 @@ DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
/* Codepoint may be original input, a decoded surrogate pair, or may
* have been replaced with U+FFFD.
*/
- enc_ctx->out += duk_unicode_encode_xutf8(codepoint, enc_ctx->out);
+ enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out);
}
#endif /* DUK_USE_ENCODING_BUILTINS */
/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8
* decoder.
*/
-DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *dec_ctx) {
+DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) {
const duk_uint8_t *input;
duk_size_t len = 0;
duk_size_t len_tmp;
@@ -30247,24 +31407,24 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *de
* required side effect order.
*/
- if (duk_is_undefined(ctx, 0)) {
- duk_push_fixed_buffer_nozero(ctx, 0);
- duk_replace(ctx, 0);
+ if (duk_is_undefined(thr, 0)) {
+ duk_push_fixed_buffer_nozero(thr, 0);
+ duk_replace(thr, 0);
}
- (void) duk_require_buffer_data(ctx, 0, &len); /* Need 'len', avoid pointer. */
+ (void) duk_require_buffer_data(thr, 0, &len); /* Need 'len', avoid pointer. */
- if (duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_UNDEFINED |
+ if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_NULL |
DUK_TYPE_MASK_NONE)) {
/* Use defaults, treat missing value like undefined. */
} else {
- duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_UNDEFINED |
+ duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_NULL |
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER |
DUK_TYPE_MASK_OBJECT);
- if (duk_get_prop_string(ctx, 1, "stream")) {
- stream = duk_to_boolean(ctx, -1);
+ if (duk_get_prop_string(thr, 1, "stream")) {
+ stream = duk_to_boolean(thr, -1);
}
}
@@ -30277,11 +31437,11 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *de
* XXX: As with TextEncoder, need a better buffer allocation strategy here.
*/
if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_RESULT_TOO_LONG);
+ DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
}
- output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, 3 + (3 * len)); /* used parts will be always manually written over */
+ output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */
- input = (const duk_uint8_t *) duk_get_buffer_data(ctx, 0, &len_tmp);
+ input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp);
DUK_ASSERT(input != NULL || len == 0);
if (DUK_UNLIKELY(len != len_tmp)) {
/* Very unlikely but possible: source buffer was resized by
@@ -30330,7 +31490,7 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *de
}
}
- out += duk_unicode_encode_cesu8(codepoint, out);
+ out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out);
DUK_ASSERT(out <= output + (3 + (3 * len)));
}
@@ -30350,11 +31510,11 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *de
/* Output buffer is fixed and thus stable even if there had been
* side effects (which there shouldn't be).
*/
- duk_push_lstring(ctx, (const char *) output, (duk_size_t) (out - output));
+ duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output));
return 1;
fail_type:
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED);
DUK_UNREACHABLE();
}
@@ -30363,38 +31523,38 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *de
*/
#if defined(DUK_USE_ENCODING_BUILTINS)
-DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) {
/* TextEncoder currently requires no persistent state, so the constructor
* does nothing on purpose.
*/
- duk_require_constructor_call(ctx);
+ duk_require_constructor_call(thr);
return 0;
}
-DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx) {
- duk_push_string(ctx, "utf-8");
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) {
+ duk_push_string(thr, "utf-8");
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
duk__encode_context enc_ctx;
duk_size_t len;
duk_size_t final_len;
duk_uint8_t *output;
- DUK_ASSERT_TOP(ctx, 1);
- if (duk_is_undefined(ctx, 0)) {
+ DUK_ASSERT_TOP(thr, 1);
+ if (duk_is_undefined(thr, 0)) {
len = 0;
} else {
duk_hstring *h_input;
- h_input = duk_to_hstring(ctx, 0);
+ h_input = duk_to_hstring(thr, 0);
DUK_ASSERT(h_input != NULL);
len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_RESULT_TOO_LONG);
+ DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
}
}
@@ -30408,10 +31568,10 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx) {
* figure out the space needed ahead of time?
*/
DUK_ASSERT(3 * len >= len);
- output = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, 3 * len);
+ output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len);
if (len > 0) {
- DUK_ASSERT(duk_is_string(ctx, 0)); /* True if len > 0. */
+ DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */
/* XXX: duk_decode_string() is used to process the input
* string. For standard Ecmascript strings, represented
@@ -30427,7 +31587,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx) {
*/
enc_ctx.lead = 0x0000L;
enc_ctx.out = output;
- duk_decode_string(ctx, 0, duk__utf8_encode_char, (void *) &enc_ctx);
+ duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx);
if (enc_ctx.lead != 0x0000L) {
/* unpaired high surrogate at end of string */
enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out);
@@ -30437,11 +31597,11 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx) {
/* The output buffer is usually very much oversized, so shrink it to
* actually needed size. Pointer stability assumed up to this point.
*/
- DUK_ASSERT_TOP(ctx, 2);
- DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(ctx, -1, NULL));
+ DUK_ASSERT_TOP(thr, 2);
+ DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL));
final_len = (duk_size_t) (enc_ctx.out - output);
- duk_resize_buffer(ctx, -1, final_len);
+ duk_resize_buffer(thr, -1, final_len);
/* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */
} else {
final_len = 0;
@@ -30454,84 +31614,84 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx) {
* returns a plain dynamic buffer.
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- duk_push_buffer_object(ctx, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
+ duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
#endif
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
duk__decode_context *dec_ctx;
duk_bool_t fatal = 0;
duk_bool_t ignore_bom = 0;
- DUK_ASSERT_TOP(ctx, 2);
- duk_require_constructor_call(ctx);
- if (!duk_is_undefined(ctx, 0)) {
+ DUK_ASSERT_TOP(thr, 2);
+ duk_require_constructor_call(thr);
+ if (!duk_is_undefined(thr, 0)) {
/* XXX: For now ignore 'label' (encoding identifier). */
- duk_to_string(ctx, 0);
+ duk_to_string(thr, 0);
}
- if (!duk_is_null_or_undefined(ctx, 1)) {
- if (duk_get_prop_string(ctx, 1, "fatal")) {
- fatal = duk_to_boolean(ctx, -1);
+ if (!duk_is_null_or_undefined(thr, 1)) {
+ if (duk_get_prop_string(thr, 1, "fatal")) {
+ fatal = duk_to_boolean(thr, -1);
}
- if (duk_get_prop_string(ctx, 1, "ignoreBOM")) {
- ignore_bom = duk_to_boolean(ctx, -1);
+ if (duk_get_prop_string(thr, 1, "ignoreBOM")) {
+ ignore_bom = duk_to_boolean(thr, -1);
}
}
- duk_push_this(ctx);
+ duk_push_this(thr);
/* The decode context is not assumed to be zeroed; all fields are
* initialized explicitly.
*/
- dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(ctx, sizeof(duk__decode_context));
+ dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context));
dec_ctx->fatal = (duk_uint8_t) fatal;
dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom;
duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */
- duk_put_prop_string(ctx, -2, "\xff" "Context");
+ duk_put_prop_string(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
return 0;
}
/* Get TextDecoder context from 'this'; leaves garbage on stack. */
-DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_context *ctx) {
+DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) {
duk__decode_context *dec_ctx;
- duk_push_this(ctx);
- duk_get_prop_string(ctx, -1, "\xff" "Context");
- dec_ctx = (duk__decode_context *) duk_require_buffer(ctx, -1, NULL);
+ duk_push_this(thr);
+ duk_get_prop_string(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
+ dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL);
DUK_ASSERT(dec_ctx != NULL);
return dec_ctx;
}
-DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) {
duk__decode_context *dec_ctx;
duk_int_t magic;
- dec_ctx = duk__get_textdecoder_context(ctx);
- magic = duk_get_current_magic(ctx);
+ dec_ctx = duk__get_textdecoder_context(thr);
+ magic = duk_get_current_magic(thr);
switch (magic) {
case 0:
/* Encoding is now fixed, so _Context lookup is only needed to
* validate the 'this' binding (TypeError if not TextDecoder-like).
*/
- duk_push_string(ctx, "utf-8");
+ duk_push_string(thr, "utf-8");
break;
case 1:
- duk_push_boolean(ctx, dec_ctx->fatal);
+ duk_push_boolean(thr, dec_ctx->fatal);
break;
default:
- duk_push_boolean(ctx, dec_ctx->ignore_bom);
+ duk_push_boolean(thr, dec_ctx->ignore_bom);
break;
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) {
duk__decode_context *dec_ctx;
- dec_ctx = duk__get_textdecoder_context(ctx);
- return duk__decode_helper(ctx, dec_ctx);
+ dec_ctx = duk__get_textdecoder_context(thr);
+ return duk__decode_helper(thr, dec_ctx);
}
#endif /* DUK_USE_ENCODING_BUILTINS */
@@ -30544,14 +31704,14 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx) {
* index 0, and decode options (not present for Buffer) at index 1. Return value
* is a Duktape/C function return value.
*/
-DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) {
duk__decode_context dec_ctx;
dec_ctx.fatal = 0; /* use replacement chars */
dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */
duk__utf8_decode_init(&dec_ctx);
- return duk__decode_helper(ctx, &dec_ctx);
+ return duk__decode_helper(thr, &dec_ctx);
}
/* automatic undefs */
@@ -30564,7 +31724,7 @@ DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx) {
/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) {
/* Behavior for constructor and non-constructor call is
* the same except for augmenting the created error. When
* called as a constructor, the caller (duk_new()) will handle
@@ -30572,25 +31732,22 @@ DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
* it here.
*/
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
+ duk_small_int_t bidx_prototype = duk_get_current_magic(thr);
/* same for both error and each subclass like TypeError */
duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
- DUK_UNREF(thr);
-
- (void) duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
+ (void) duk_push_object_helper(thr, flags_and_class, bidx_prototype);
/* If message is undefined, the own property 'message' is not set at
* all to save property space. An empty message is inherited anyway.
*/
- if (!duk_is_undefined(ctx, 0)) {
- duk_to_string(ctx, 0);
- duk_dup_0(ctx); /* [ message error message ] */
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
+ if (!duk_is_undefined(thr, 0)) {
+ duk_to_string(thr, 0);
+ duk_dup_0(thr); /* [ message error message ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
}
/* Augment the error if called as a normal function. __FILE__ and __LINE__
@@ -30598,28 +31755,28 @@ DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
- if (!duk_is_constructor_call(ctx)) {
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
+ if (!duk_is_constructor_call(thr)) {
+ duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE);
}
#endif
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
/* XXX: optimize with more direct internal access */
- duk_push_this(ctx);
- (void) duk_require_hobject_promote_mask(ctx, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ duk_push_this(thr);
+ (void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
/* [ ... this ] */
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_string(ctx, "Error");
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_push_string(thr, "Error");
} else {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
/* [ ... this name ] */
@@ -30628,28 +31785,28 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
* accident or are they actually needed? The first ToString()
* could conceivably return 'undefined'.
*/
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_hstring_empty(ctx);
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_push_hstring_empty(thr);
} else {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
/* [ ... this name message ] */
- if (duk_get_length(ctx, -2) == 0) {
+ if (duk_get_length(thr, -2) == 0) {
/* name is empty -> return message */
return 1;
}
- if (duk_get_length(ctx, -1) == 0) {
+ if (duk_get_length(thr, -1) == 0) {
/* message is empty -> return name */
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
}
- duk_push_string(ctx, ": ");
- duk_insert(ctx, -2); /* ... name ': ' message */
- duk_concat(ctx, 3);
+ duk_push_string(thr, ": ");
+ duk_insert(thr, -2); /* ... name ': ' message */
+ duk_concat(thr, 3);
return 1;
}
@@ -30675,8 +31832,7 @@ 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__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) {
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 */
@@ -30688,39 +31844,38 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
const char *str_directeval = " directeval";
const char *str_empty = "";
- DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
- DUK_UNREF(thr);
+ DUK_ASSERT_TOP(thr, 0); /* fixed arg count */
- duk_push_this(ctx);
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
- idx_td = duk_get_top_index(ctx);
+ duk_push_this(thr);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA);
+ idx_td = duk_get_top_index(thr);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
- duk_push_this(ctx);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE);
+ duk_push_this(thr);
/* [ ... this tracedata sep this ] */
/* XXX: skip null filename? */
- if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
+ if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) {
/* Current tracedata contains 2 entries per callstack entry. */
for (i = 0; ; i += 2) {
duk_int_t pc;
- duk_int_t line;
- duk_int_t flags;
+ duk_uint_t line;
+ duk_uint_t flags;
duk_double_t d;
const char *funcname;
const char *filename;
duk_hobject *h_func;
duk_hstring *h_name;
- duk_require_stack(ctx, 5);
- duk_get_prop_index(ctx, idx_td, i);
- duk_get_prop_index(ctx, idx_td, i + 1);
- d = duk_to_number_m1(ctx);
+ duk_require_stack(thr, 5);
+ duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i);
+ duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1));
+ d = duk_to_number_m1(thr);
pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
- flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
- t = (duk_small_int_t) duk_get_type(ctx, -2);
+ flags = (duk_uint_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
+ t = (duk_small_int_t) duk_get_type(thr, -2);
if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
/*
@@ -30731,17 +31886,15 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
/* [ ... v1(func) v2(pc+flags) ] */
- h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
-
/* These may be systematically omitted by Duktape
* with certain config options, but allow user to
* set them on a case-by-case basis.
*/
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME);
- duk_get_prop_stridx_short(ctx, -3, DUK_STRIDX_FILE_NAME);
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
+ duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME);
#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
+ line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc);
#else
line = 0;
#endif
@@ -30751,27 +31904,29 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
/* When looking for .fileName/.lineNumber, blame first
* function which has a .fileName.
*/
- if (duk_is_string_notsymbol(ctx, -1)) {
+ if (duk_is_string_notsymbol(thr, -1)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, line);
+ duk_push_uint(thr, line);
return 1;
}
}
/* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
/* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
- h_name = duk_get_hstring_notsymbol(ctx, -2); /* may be NULL */
+ h_name = duk_get_hstring_notsymbol(thr, -2); /* may be NULL */
funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
"[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
- filename = duk_get_string_notsymbol(ctx, -1);
+ filename = duk_get_string_notsymbol(thr, -1);
filename = filename ? filename : "";
DUK_ASSERT(funcname != NULL);
DUK_ASSERT(filename != NULL);
+ h_func = duk_get_hobject(thr, -4); /* NULL for lightfunc */
+
if (h_func == NULL) {
- duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
+ duk_push_sprintf(thr, "at %s light%s%s%s%s%s",
(const char *) funcname,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
@@ -30779,7 +31934,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
} else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
- duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
+ duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
@@ -30788,18 +31943,18 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
} else {
- duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
+ duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
- (long) line,
+ (unsigned long) line,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
}
- duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
- duk_pop_3(ctx); /* -> [ ... str ] */
+ duk_replace(thr, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
+ duk_pop_3(thr); /* -> [ ... str ] */
} else if (t == DUK_TYPE_STRING) {
const char *str_file;
@@ -30816,10 +31971,10 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
*/
if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, pc);
+ duk_push_int(thr, pc);
return 1;
}
}
@@ -30829,14 +31984,14 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* don't need to be explicitly rejected as they pose no memory
* safety issues.
*/
- str_file = (const char *) duk_get_string(ctx, -2);
- duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
+ str_file = (const char *) duk_get_string(thr, -2);
+ duk_push_sprintf(thr, "at [anon] (%s:%ld) internal",
(const char *) (str_file ? str_file : "null"), (long) pc);
- duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
- duk_pop(ctx); /* -> [ ... str ] */
+ duk_replace(thr, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
+ duk_pop(thr); /* -> [ ... str ] */
} else {
/* unknown, ignore */
- duk_pop_2(ctx);
+ duk_pop_2(thr);
break;
}
}
@@ -30846,7 +32001,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* marker so this is the best we can do.
*/
- duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS);
}
}
@@ -30859,7 +32014,7 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* duk_join() automatically. We don't want to do that
* coercion when providing .fileName or .lineNumber (GH-254).
*/
- duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
+ duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/);
return 1;
}
}
@@ -30868,16 +32023,16 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t o
* 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__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
+ return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER);
}
#else /* DUK_USE_TRACEBACKS */
@@ -30894,26 +32049,26 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx
* of the error so this makes sense.
*/
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
/* XXX: remove this native function and map 'stack' accessor
* to the toString() implementation directly.
*/
- return duk_bi_error_prototype_to_string(ctx);
+ return duk_bi_error_prototype_to_string(thr);
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
+ DUK_UNREF(thr);
return 0;
}
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
+ DUK_UNREF(thr);
return 0;
}
#endif /* DUK_USE_TRACEBACKS */
-DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
+DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, 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
@@ -30921,34 +32076,34 @@ DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t
* See https://github.com/svaarala/duktape/issues/387.
*/
- DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
+ DUK_ASSERT_TOP(thr, 1); /* fixed arg count: value */
- duk_push_this(ctx);
- duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
- duk_dup_0(ctx);
+ duk_push_this(thr);
+ duk_push_hstring_stridx(thr, stridx_key);
+ duk_dup_0(thr);
/* [ ... 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_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1)));
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
+ duk_def_prop(thr, -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_stack_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, 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_filename_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, 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);
+DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) {
+ return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER);
}
/* automatic undefs */
@@ -30962,15 +32117,14 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx
/* #include duk_internal.h -> already included */
/* Needed even when Function built-in is disabled. */
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) {
/* ignore arguments, return undefined (E5 Section 15.3.4) */
- DUK_UNREF(ctx);
+ DUK_UNREF(thr);
return 0;
}
#if defined(DUK_USE_FUNCTION_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
duk_hstring *h_sourcecode;
duk_idx_t nargs;
duk_idx_t i;
@@ -30981,57 +32135,57 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
/* normal and constructor calls have identical semantics */
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
for (i = 0; i < nargs; i++) {
- duk_to_string(ctx, i); /* Rejects Symbols during coercion. */
+ duk_to_string(thr, i); /* Rejects Symbols during coercion. */
}
if (nargs == 0) {
- duk_push_hstring_empty(ctx);
- duk_push_hstring_empty(ctx);
+ duk_push_hstring_empty(thr);
+ duk_push_hstring_empty(thr);
} else if (nargs == 1) {
/* XXX: cover this with the generic >1 case? */
- duk_push_hstring_empty(ctx);
+ duk_push_hstring_empty(thr);
} else {
- duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
- duk_push_string(ctx, ",");
- duk_insert(ctx, 1);
- duk_join(ctx, nargs - 1);
+ duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
+ duk_push_string(thr, ",");
+ duk_insert(thr, 1);
+ duk_join(thr, nargs - 1);
}
/* [ body formals ], formals is comma separated list that needs to be parsed */
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
/* XXX: this placeholder is not always correct, but use for now.
* It will fail in corner cases; see test-dev-func-cons-args.js.
*/
- duk_push_string(ctx, "function(");
- duk_dup_1(ctx);
- duk_push_string(ctx, "){");
- duk_dup_0(ctx);
- duk_push_string(ctx, "}");
- duk_concat(ctx, 5);
+ duk_push_string(thr, "function(");
+ duk_dup_1(thr);
+ duk_push_string(thr, "){");
+ duk_dup_0(thr);
+ duk_push_string(thr, "}");
+ duk_concat(thr, 5);
/* [ body formals source ] */
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
/* strictness is not inherited, intentional */
comp_flags = DUK_COMPILE_FUNCEXPR;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
- h_sourcecode = duk_require_hstring(ctx, -2); /* no symbol check needed; -2 is concat'd code */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
+ h_sourcecode = duk_require_hstring(thr, -2); /* no symbol check needed; -2 is concat'd code */
duk_js_compile(thr,
(const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
(duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
comp_flags);
/* Force .name to 'anonymous' (ES2015). */
- duk_push_string(ctx, "anonymous");
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+ duk_push_string(thr, "anonymous");
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
- func = (duk_hcompfunc *) duk_known_hobject(ctx, -1);
+ func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func));
@@ -31053,7 +32207,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
#endif /* DUK_USE_FUNCTION_BUILTIN */
#if defined(DUK_USE_FUNCTION_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
/*
@@ -31076,8 +32230,8 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
* [lightfunc code].
*/
- duk_push_this(ctx);
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ duk_push_this(thr);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
@@ -31091,25 +32245,25 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
* if the name contained a suitable prefix followed by '//' it
* might cause the result to parse without error.
*/
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
+ if (duk_is_undefined(thr, -1)) {
func_name = "";
} else {
- func_name = duk_to_string(ctx, -1);
+ func_name = duk_to_string(thr, -1);
DUK_ASSERT(func_name != NULL);
}
if (DUK_HOBJECT_IS_COMPFUNC(obj)) {
- duk_push_sprintf(ctx, "function %s() { [ecmascript code] }", (const char *) func_name);
+ duk_push_sprintf(thr, "function %s() { [ecmascript code] }", (const char *) func_name);
} else if (DUK_HOBJECT_IS_NATFUNC(obj)) {
- duk_push_sprintf(ctx, "function %s() { [native code] }", (const char *) func_name);
+ duk_push_sprintf(thr, "function %s() { [native code] }", (const char *) func_name);
} else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) {
- duk_push_sprintf(ctx, "function %s() { [bound code] }", (const char *) func_name);
+ duk_push_sprintf(thr, "function %s() { [bound code] }", (const char *) func_name);
} else {
goto type_error;
}
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_push_lightfunc_tostring(ctx, tv);
+ duk_push_lightfunc_tostring(thr, tv);
} else {
goto type_error;
}
@@ -31117,266 +32271,287 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
return 1;
type_error:
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
#endif
-#if defined(DUK_USE_FUNCTION_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
- /*
- * magic = 0: Function.prototype.apply()
- * magic = 1: Reflect.apply()
- * magic = 2: Reflect.construct()
+/* Always present because the native function pointer is needed in call
+ * handling.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) {
+ /* .call() is dealt with in call handling by simulating its
+ * effects so this function is actually never called.
*/
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
- duk_idx_t idx_args;
- duk_idx_t len;
- duk_idx_t i;
- duk_int_t magic;
- duk_idx_t nargs;
- duk_uint_t mask;
-
- magic = duk_get_current_magic(ctx);
- switch (magic) {
- case 0: /* Function.prototype.apply() */
- DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
- duk_push_this(ctx);
- duk_insert(ctx, 0);
- /* Fall through intentionally for shared handling. */
- case 1: /* Reflect.apply(); Function.prototype.apply() after 'this' fixup. */
- DUK_ASSERT_TOP(ctx, 3); /* not a vararg function */
- idx_args = 2;
- duk_require_callable(ctx, 0);
- break;
- default: /* Reflect.construct() */
- DUK_ASSERT(magic == 2);
- duk_require_constructable(ctx, 0);
- nargs = duk_get_top(ctx);
- if (nargs < 2) {
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
- }
- if (nargs >= 3 && !duk_strict_equals(ctx, 0, 2)) {
- /* XXX: [[Construct]] newTarget currently unsupported */
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
- }
- idx_args = 1;
- break;
- }
-
- if (magic != 2) {
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
- } else {
- /* thisArg is not applicable for Reflect.construct(). */
- DUK_DDD(DUK_DDDPRINT("func=%!iT, argArray=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
- }
-
- /* [ func thisArg? argArray ] */
-
- mask = duk_get_type_mask(ctx, idx_args);
- if (mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) {
- DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
- len = 0;
- } else if (mask & DUK_TYPE_MASK_OBJECT) {
- DUK_DDD(DUK_DDDPRINT("argArray is an object"));
-
- /* XXX: make this an internal helper */
- DUK_ASSERT(idx_args >= 0 && idx_args <= 0x7fffL); /* short variants would work, but avoid shifting */
- duk_get_prop_stridx(ctx, idx_args, DUK_STRIDX_LENGTH);
- len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
- duk_pop(ctx);
-
- duk_require_stack(ctx, len);
-
- DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
- for (i = 0; i < len; i++) {
- duk_get_prop_index(ctx, idx_args, i);
- }
- } else {
- goto type_error;
- }
- duk_remove(ctx, idx_args);
- DUK_ASSERT_TOP(ctx, idx_args + len);
-
- /* [ func thisArg? arg1 ... argN ] */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
- if (magic != 2) {
- /* Function.prototype.apply() or Reflect.apply() */
- DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) len));
- duk_call_method(ctx, len);
- } else {
- /* Reflect.construct() */
- DUK_DDD(DUK_DDDPRINT("construct, func=%!iT, len=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (long) len));
- duk_new(ctx, len);
- }
- return 1;
+DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
+}
- type_error:
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) {
+ /* Like .call(), never actually called. */
+ DUK_UNREF(thr);
+ return DUK_RET_TYPE_ERROR;
}
-#endif
#if defined(DUK_USE_FUNCTION_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
- duk_idx_t nargs;
+/* Create a bound function which points to a target function which may
+ * be bound or non-bound. If the target is bound, the argument lists
+ * and 'this' binding of the functions are merged and the resulting
+ * function points directly to the non-bound target.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
+ duk_hboundfunc *h_bound;
+ duk_idx_t nargs; /* bound args, not counting 'this' binding */
+ duk_idx_t bound_nargs;
+ duk_int_t bound_len;
+ duk_tval *tv_prevbound;
+ duk_idx_t n_prevbound;
+ duk_tval *tv_res;
+ duk_tval *tv_tmp;
- /* Step 1 is not necessary because duk_call_method() will take
- * care of it.
- */
+ /* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */
- /* vararg function, thisArg needs special handling */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
+ /* Vararg function, careful arg handling, e.g. thisArg may not
+ * be present.
+ */
+ nargs = duk_get_top(thr) - 1; /* actual args, not counting 'this' binding */
+ if (nargs < 0) {
nargs++;
+ duk_push_undefined(thr);
}
- DUK_ASSERT(nargs >= 1);
+ DUK_ASSERT(nargs >= 0);
- /* [ thisArg arg1 ... argN ] */
-
- duk_push_this(ctx); /* 'func' in the algorithm */
- duk_insert(ctx, 0);
+ /* Limit 'nargs' for bound functions to guarantee arithmetic
+ * below will never wrap.
+ */
+ if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
+ DUK_DCERROR_RANGE_INVALID_COUNT(thr);
+ }
- /* [ func thisArg arg1 ... argN ] */
+ duk_push_this(thr);
+ duk_require_callable(thr, -1);
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) (nargs - 1),
- (long) duk_get_top(ctx)));
- duk_call_method(ctx, nargs - 1);
- return 1;
-}
-#endif /* DUK_USE_FUNCTION_BUILTIN */
+ /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs+1 total) */
+ DUK_ASSERT_TOP(thr, nargs + 2);
-#if defined(DUK_USE_FUNCTION_BUILTIN)
-/* XXX: the implementation now assumes "chained" bound functions,
- * whereas "collapsed" bound functions (where there is ever only
- * one bound function which directly points to a non-bound, final
- * function) would require a "collapsing" implementation which
- * merges argument lists etc here.
- */
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_bound;
- duk_hobject *h_target;
- duk_idx_t nargs;
- duk_idx_t i;
+ /* Create bound function object. */
+ h_bound = duk_push_hboundfunc(thr);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding));
+ DUK_ASSERT(h_bound->args == NULL);
+ DUK_ASSERT(h_bound->nargs == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL);
- /* vararg function, careful arg handling (e.g. thisArg may not be present) */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
- nargs++;
- }
- DUK_ASSERT(nargs >= 1);
+ /* [ thisArg arg1 ... argN func boundFunc ] */
- duk_push_this(ctx);
- duk_require_callable(ctx, -1);
+ /* If the target is a bound function, argument lists must be
+ * merged. The 'this' binding closest to the target function
+ * wins because in call handling the 'this' gets replaced over
+ * and over again until we call the non-bound function.
+ */
+ tv_prevbound = NULL;
+ n_prevbound = 0;
+ tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0);
+ DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp);
+ tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2);
+ DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp);
- /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
- DUK_ASSERT_TOP(ctx, nargs + 1);
+ if (DUK_TVAL_IS_OBJECT(tv_tmp)) {
+ duk_hobject *h_target;
+ duk_hobject *bound_proto;
- /* create bound function object */
- h_bound = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_FASTREFS |
- DUK_HOBJECT_FLAG_BOUNDFUNC |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
- DUK_BIDX_FUNCTION_PROTOTYPE);
- DUK_ASSERT(h_bound != NULL);
+ h_target = DUK_TVAL_GET_OBJECT(tv_tmp);
+ DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target));
- /* [ thisArg arg1 ... argN func boundFunc ] */
- duk_dup_m2(ctx); /* func */
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
+ /* Internal prototype must be copied from the target.
+ * For lightfuncs Function.prototype is used and is already
+ * in place.
+ */
+ bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target);
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
- duk_dup_0(ctx); /* thisArg */
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
+ /* The 'strict' flag is copied to get the special [[Get]] of E5.1
+ * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
+ * function. Not sure if this is correct, because the specification
+ * is a bit ambiguous on this point but it would make sense.
+ */
+ /* Strictness is inherited from target. */
+ if (DUK_HOBJECT_HAS_STRICT(h_target)) {
+ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
+ }
- duk_push_array(ctx);
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) {
+ duk_hboundfunc *h_boundtarget;
- /* [ thisArg arg1 ... argN func boundFunc argArray ] */
+ h_boundtarget = (duk_hboundfunc *) h_target;
- for (i = 0; i < nargs - 1; i++) {
- duk_dup(ctx, 1 + i);
- duk_put_prop_index(ctx, -2, i);
- }
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
+ /* The final function should always be non-bound, unless
+ * there's a bug in the internals. Assert for it.
+ */
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) ||
+ (DUK_TVAL_IS_OBJECT(&h_boundtarget->target) &&
+ DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) &&
+ !DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target))));
- /* [ thisArg arg1 ... argN func boundFunc ] */
+ DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target);
+ DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding);
- h_target = duk_get_hobject(ctx, -2);
+ tv_prevbound = h_boundtarget->args;
+ n_prevbound = h_boundtarget->nargs;
+ }
+ } else {
+ /* Lightfuncs are always strict. */
+ duk_hobject *bound_proto;
- /* internal prototype must be copied from the target */
- if (h_target != NULL) {
- /* For lightfuncs Function.prototype is used and is already in place. */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_bound, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target));
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
+ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
+ bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
}
- /* bound function 'length' property is interesting */
- if (h_target == NULL || /* lightfunc */
- DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
- /* For lightfuncs, simply read the virtual property. */
- duk_int_t tmp;
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH);
- tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
- duk_pop(ctx);
- duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
- } else {
- duk_push_int(ctx, 0);
+ DUK_TVAL_INCREF(thr, &h_bound->target); /* old values undefined, no decref needed */
+ DUK_TVAL_INCREF(thr, &h_bound->this_binding);
+
+ bound_nargs = n_prevbound + nargs;
+ if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
+ DUK_DCERROR_RANGE_INVALID_COUNT(thr);
}
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */
+ tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval));
+ DUK_ASSERT(tv_res != NULL);
+ DUK_ASSERT(h_bound->args == NULL);
+ DUK_ASSERT(h_bound->nargs == 0);
+ h_bound->args = tv_res;
+ h_bound->nargs = bound_nargs;
- /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER);
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS);
+ DUK_ASSERT(n_prevbound >= 0);
+ duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound);
+ DUK_ASSERT(nargs >= 0);
+ duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs);
- /* XXX: 'copy properties' API call? */
-#if defined(DUK_USE_FUNC_NAME_PROPERTY)
- duk_push_string(ctx, "bound "); /* ES2015 19.2.3.2. */
- duk_get_prop_stridx_short(ctx, -3, DUK_STRIDX_NAME);
- if (!duk_is_string_notsymbol(ctx, -1)) {
+ /* [ thisArg arg1 ... argN func boundFunc ] */
+
+ /* Bound function 'length' property is interesting.
+ * For lightfuncs, simply read the virtual property.
+ */
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH);
+ bound_len = duk_get_int(thr, -1); /* ES2015: no coercion */
+ if (bound_len < nargs) {
+ bound_len = 0;
+ } else {
+ bound_len -= nargs;
+ }
+ if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) {
+ bound_len = (duk_int_t) DUK_UINT32_MAX;
+ }
+ duk_pop(thr);
+ DUK_ASSERT(bound_len >= 0);
+ tv_tmp = thr->valstack_top++;
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp));
+ DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len); /* in-place update, fastint */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */
+
+ /* XXX: could these be virtual? */
+ /* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */
+ duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER);
+ duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS);
+
+ /* Function name and fileName (non-standard). */
+ duk_push_string(thr, "bound "); /* ES2015 19.2.3.2. */
+ duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME);
+ if (!duk_is_string_notsymbol(thr, -1)) {
/* ES2015 has requirement to check that .name of target is a string
* (also must check for Symbol); if not, targetName should be the
* empty string. ES2015 19.2.3.2.
*/
- duk_pop(ctx);
- duk_push_hstring_empty(ctx);
+ duk_pop(thr);
+ duk_push_hstring_empty(thr);
}
- duk_concat(ctx, 2);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
-#endif
+ duk_concat(thr, 2);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
#endif
- /* The 'strict' flag is copied to get the special [[Get]] of E5.1
- * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
- * function. Not sure if this is correct, because the specification
- * is a bit ambiguous on this point but it would make sense.
- */
- if (h_target == NULL) {
- /* Lightfuncs are always strict. */
- DUK_HOBJECT_SET_STRICT(h_bound);
- } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
- DUK_HOBJECT_SET_STRICT(h_bound);
- }
- DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
#endif /* DUK_USE_FUNCTION_BUILTIN */
+
+/* %NativeFunctionPrototype% .length getter. */
+DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hnatfunc *h;
+ duk_int16_t func_nargs;
+
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
+
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
+ goto fail_type;
+ }
+ func_nargs = h->nargs;
+ duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ duk_small_uint_t lf_flags;
+ duk_small_uint_t lf_len;
+
+ lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
+ lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
+ duk_push_uint(thr, lf_len);
+ } else {
+ goto fail_type;
+ }
+ return 1;
+
+ fail_type:
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+}
+
+/* %NativeFunctionPrototype% .name getter. */
+DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_hnatfunc *h;
+
+ tv = duk_get_borrowed_this_tval(thr);
+ DUK_ASSERT(tv != NULL);
+
+ if (DUK_TVAL_IS_OBJECT(tv)) {
+ h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
+ DUK_ASSERT(h != NULL);
+ if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
+ goto fail_type;
+ }
+#if 0
+ duk_push_hnatfunc_name(thr, h);
+#endif
+ duk_push_hstring_empty(thr);
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+ duk_push_lightfunc_name(thr, tv);
+ } else {
+ goto fail_type;
+ }
+ return 1;
+
+ fail_type:
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+}
/*
* Global object built-ins
*/
@@ -31492,15 +32667,14 @@ 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, const void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL int duk__transform_helper(duk_hthread *thr, duk__transform_callback callback, const void *udata) {
duk__transform_context tfm_ctx_alloc;
duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
duk_codepoint_t cp;
tfm_ctx->thr = thr;
- tfm_ctx->h_str = duk_to_hstring(ctx, 0);
+ tfm_ctx->h_str = duk_to_hstring(thr, 0);
DUK_ASSERT(tfm_ctx->h_str != NULL);
DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
@@ -31516,7 +32690,7 @@ DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback ca
DUK_BW_COMPACT(thr, &tfm_ctx->bw);
- (void) duk_buffer_to_string(ctx, -1); /* Safe if transform is safe. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe if transform is safe. */
return 1;
}
@@ -31549,7 +32723,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
goto uri_error;
}
cp1 = cp;
- cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
+ cp = (duk_codepoint_t) (((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L);
} else if (cp > 0x10ffffL) {
/* Although we can allow non-BMP characters (they'll decode
* back into surrogate pairs), we don't allow extended UTF-8
@@ -31707,7 +32881,7 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct
DUK_ASSERT(cp < 0x100000L);
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
- DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L));
+ DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffL) + 0xdc00L));
} else {
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
}
@@ -31795,20 +32969,19 @@ DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx,
* calling activation at all which needs careful handling.
*/
-DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) {
duk_hstring *h;
duk_activation *act_caller;
duk_activation *act_eval;
- duk_activation *act;
duk_hcompfunc *func;
duk_hobject *outer_lex_env;
duk_hobject *outer_var_env;
duk_bool_t this_to_global = 1;
duk_small_uint_t comp_flags;
duk_int_t level = -2;
+ duk_small_uint_t call_flags;
- DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
+ DUK_ASSERT(duk_get_top(thr) == 1 || duk_get_top(thr) == 2); /* 2 when called by debugger */
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
DUK_ASSERT(thr->callstack_curr != NULL);
DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
@@ -31822,7 +32995,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* activation doesn't exist, call must be indirect.
*/
- h = duk_get_hstring_notsymbol(ctx, 0);
+ h = duk_get_hstring_notsymbol(thr, 0);
if (!h) {
/* Symbol must be returned as is, like any non-string values. */
return 1; /* return arg as-is */
@@ -31833,8 +33006,8 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
* 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);
+ if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) {
+ level = duk_get_int(thr, 1);
}
DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
#endif
@@ -31844,11 +33017,11 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
comp_flags = DUK_COMPILE_EVAL;
act_eval = thr->callstack_curr; /* this function */
DUK_ASSERT(act_eval != NULL);
- if (thr->callstack_top >= (duk_size_t) -level) {
+ act_caller = duk_hthread_get_activation_for_level(thr, level);
+ if (act_caller != NULL) {
/* Have a calling activation, check for direct eval (otherwise
* assume indirect eval.
*/
- 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
@@ -31859,35 +33032,31 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
} else {
DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
}
- act_caller = NULL; /* avoid dereference after potential callstack realloc */
- act_eval = NULL;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
duk_js_compile(thr,
(const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
(duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
comp_flags);
- func = (duk_hcompfunc *) duk_known_hobject(ctx, -1);
+ func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
/* [ source template ] */
/* E5 Section 10.4.2 */
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack_curr; /* this function */
- if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+
+ if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
+ DUK_ASSERT(act_caller != NULL);
+ if (act_caller->lex_env == NULL) {
+ DUK_ASSERT(act_caller->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 + level;
+ duk_js_init_activation_environment_records_delayed(thr, act_caller);
}
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
+ DUK_ASSERT(act_caller->lex_env != NULL);
+ DUK_ASSERT(act_caller->var_env != NULL);
this_to_global = 0;
@@ -31899,14 +33068,13 @@ 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_lex_env = act->lex_env;
- act = NULL; /* invalidated */
+ act_lex_env = act_caller->lex_env;
new_env = duk_hdecenv_alloc(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
- duk_push_hobject(ctx, (duk_hobject *) new_env);
+ duk_push_hobject(thr, (duk_hobject *) new_env);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act_lex_env);
@@ -31916,7 +33084,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
outer_lex_env = (duk_hobject *) new_env;
outer_var_env = (duk_hobject *) new_env;
- duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
+ duk_insert(thr, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
/* compiler's responsibility */
DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
@@ -31925,8 +33093,8 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
"var_env and lex_env to caller's envs, "
"this_binding to caller's this_binding"));
- outer_lex_env = act->lex_env;
- outer_var_env = act->var_env;
+ outer_lex_env = act_caller->lex_env;
+ outer_var_env = act_caller->var_env;
/* compiler's responsibility */
DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
@@ -31939,7 +33107,6 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
}
- act = NULL;
/* Eval code doesn't need an automatic .prototype object. */
duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
@@ -31948,24 +33115,34 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
if (this_to_global) {
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
+ duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
} else {
duk_tval *tv;
DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
+ DUK_ASSERT(act_caller != NULL);
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act_caller->bottom_byteoff - sizeof(duk_tval)); /* this is just beneath bottom */
DUK_ASSERT(tv >= thr->valstack);
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
}
DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
(duk_heaphdr *) outer_lex_env,
(duk_heaphdr *) outer_var_env,
- duk_get_tval(ctx, -1)));
+ duk_get_tval(thr, -1)));
/* [ env? source template closure this ] */
- duk_call_method(ctx, 0);
+ call_flags = 0;
+ if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+ /* Set DIRECT_EVAL flag for the call; it's not strictly
+ * needed for the 'inner' eval call (the eval body) but
+ * current new.target implementation expects to find it
+ * so it can traverse direct eval chains up to the real
+ * calling function.
+ */
+ call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
+ }
+ duk_handle_call_unprotected_nargs(thr, 0, call_flags);
/* [ env? source template result ] */
@@ -31977,14 +33154,14 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
*/
#if defined(DUK_USE_GLOBAL_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) {
duk_int32_t radix;
duk_small_uint_t s2n_flags;
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, 0); /* Reject symbols. */
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, 0); /* Reject symbols. */
- radix = duk_to_int32(ctx, 1);
+ radix = duk_to_int32(thr, 1);
/* While parseInt() recognizes 0xdeadbeef, it doesn't recognize
* ES2015 0o123 or 0b10001.
@@ -32014,25 +33191,22 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
radix = 10;
}
- duk_dup_0(ctx);
- duk_numconv_parse(ctx, radix, s2n_flags);
+ duk_dup_0(thr);
+ duk_numconv_parse(thr, (duk_small_int_t) radix, s2n_flags);
return 1;
ret_nan:
- duk_push_nan(ctx);
+ duk_push_nan(thr);
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
#if defined(DUK_USE_GLOBAL_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) {
duk_small_uint_t s2n_flags;
- duk_int32_t radix;
-
- DUK_ASSERT_TOP(ctx, 1);
- duk_to_string(ctx, 0); /* Reject symbols. */
- radix = 10;
+ DUK_ASSERT_TOP(thr, 1);
+ duk_to_string(thr, 0); /* Reject symbols. */
/* XXX: check flags */
s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
@@ -32046,7 +33220,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
- duk_numconv_parse(ctx, radix, s2n_flags);
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
@@ -32056,17 +33230,17 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
*/
#if defined(DUK_USE_GLOBAL_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISNAN(d));
+DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) {
+ duk_double_t d = duk_to_number(thr, 0);
+ duk_push_boolean(thr, (duk_bool_t) DUK_ISNAN(d));
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
#if defined(DUK_USE_GLOBAL_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISFINITE(d));
+DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) {
+ duk_double_t d = duk_to_number(thr, 0);
+ duk_push_boolean(thr, (duk_bool_t) DUK_ISFINITE(d));
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
@@ -32076,29 +33250,29 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
*/
#if defined(DUK_USE_GLOBAL_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) {
+ return duk__transform_helper(thr, 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, (const void *) duk__decode_uri_component_reserved_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_hthread *thr) {
+ return duk__transform_helper(thr, 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, (const void *) duk__encode_uriunescaped_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) {
+ return duk__transform_helper(thr, 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, (const void *) duk__encode_uricomponent_unescaped_table);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
}
#if defined(DUK_USE_SECTION_B)
-DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) {
+ return duk__transform_helper(thr, 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, (const void *) NULL);
+DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) {
+ return duk__transform_helper(thr, duk__transform_callback_unescape, (const void *) NULL);
}
#endif /* DUK_USE_SECTION_B */
#endif /* DUK_USE_GLOBAL_BUILTIN */
@@ -32190,7 +33364,7 @@ DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_buf
#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
#endif
-DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
+DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth);
/*
* Helper tables
@@ -32389,7 +33563,7 @@ DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx,
DUK_ASSERT(duk_hex_dectab[0] == -1);
t = duk_hex_dectab[x & 0xff];
if (DUK_LIKELY(t >= 0)) {
- res = (res * 16) + t;
+ res = (res * 16) + (duk_uint_fast32_t) t;
} else {
/* catches EOF and invalid digits */
goto syntax_error;
@@ -32493,7 +33667,6 @@ DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_u
DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
duk_uint8_t *q;
@@ -32586,7 +33759,7 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
- (void) duk_buffer_to_string(ctx, -1); /* Safe if input string is safe. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe if input string is safe. */
/* [ ... str ] */
@@ -32603,7 +33776,6 @@ DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
*/
DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_small_int_t x;
@@ -32636,7 +33808,7 @@ DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
p++;
}
- duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
+ duk_push_lstring(thr, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
js_ctx->p = p;
/* [ ... str ] */
@@ -32646,7 +33818,6 @@ DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
#if defined(DUK_USE_JX)
DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_small_int_t x;
void *voidptr;
@@ -32684,7 +33855,7 @@ DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
voidptr = NULL;
(void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
- duk_push_pointer(ctx, voidptr);
+ duk_push_pointer(thr, voidptr);
js_ctx->p = p + 1; /* skip ')' */
/* [ ... ptr ] */
@@ -32700,7 +33871,6 @@ DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
#if defined(DUK_USE_JX)
DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
const duk_uint8_t *p;
duk_uint8_t *buf;
duk_size_t src_len;
@@ -32739,10 +33909,10 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
/* XXX: this is not very nice; unnecessary copy is made. */
src_len = (duk_size_t) (p - js_ctx->p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, src_len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len);
DUK_ASSERT(buf != NULL);
DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
- duk_hex_decode(ctx, -1);
+ duk_hex_decode(thr, -1);
js_ctx->p = p + 1; /* skip '|' */
@@ -32758,7 +33928,7 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
/* Parse a number, other than NaN or +/- Infinity */
DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
const duk_uint8_t *p_start;
const duk_uint8_t *p;
duk_uint8_t x;
@@ -32803,35 +33973,35 @@ DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
js_ctx->p = p;
DUK_ASSERT(js_ctx->p > p_start);
- duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start));
+ duk_push_lstring(thr, (const char *) p_start, (duk_size_t) (p - p_start));
s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
DUK_S2N_FLAG_ALLOW_FRAC;
DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
- if (duk_is_nan(ctx, -1)) {
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
+ if (duk_is_nan(thr, -1)) {
duk__dec_syntax_error(js_ctx);
}
- DUK_ASSERT(duk_is_number(ctx, -1));
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... num ] */
}
DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
+ duk_hthread *thr = js_ctx->thr;
+ duk_require_stack(thr, DUK_JSON_DEC_REQSTACK);
/* c recursion check */
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT);
+ DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT);
}
js_ctx->recursion_depth++;
}
@@ -32845,7 +34015,7 @@ DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_int_t key_count; /* XXX: a "first" flag would suffice */
duk_uint8_t x;
@@ -32853,7 +34023,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
duk__dec_objarr_entry(js_ctx);
- duk_push_object(ctx);
+ duk_push_object(thr);
/* Initial '{' has been checked and eaten by caller. */
@@ -32862,7 +34032,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
x = duk__dec_get_nonwhite(js_ctx);
DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) x, (long) key_count));
/* handle comma and closing brace */
@@ -32907,7 +34077,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
/* [ ... obj key val ] */
- duk_xdef_prop_wec(ctx, -3);
+ duk_xdef_prop_wec(thr, -3);
/* [ ... obj ] */
@@ -32917,7 +34087,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
/* [ ... obj ] */
DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_objarr_exit(js_ctx);
return;
@@ -32928,7 +34098,7 @@ DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_uarridx_t arr_idx;
duk_uint8_t x;
@@ -32936,7 +34106,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
duk__dec_objarr_entry(js_ctx);
- duk_push_array(ctx);
+ duk_push_array(thr);
/* Initial '[' has been checked and eaten by caller. */
@@ -32945,7 +34115,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
x = duk__dec_get_nonwhite(js_ctx);
DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) x, (long) arr_idx));
/* handle comma and closing bracket */
@@ -32972,7 +34142,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
/* [ ... arr val ] */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
+ duk_xdef_prop_index_wec(thr, -2, arr_idx);
arr_idx++;
}
@@ -32980,12 +34150,12 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
* set the values.
*/
- duk_set_length(ctx, -1, arr_idx);
+ duk_set_length(thr, -1, arr_idx);
/* [ ... arr ] */
DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_objarr_exit(js_ctx);
return;
@@ -32996,7 +34166,7 @@ DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
}
DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_uint8_t x;
x = duk__dec_get_nonwhite(js_ctx);
@@ -33011,7 +34181,7 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
#if defined(DUK_USE_JX)
if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
- duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
+ duk_push_number(thr, -DUK_DOUBLE_INFINITY);
} else {
#else
{ /* unconditional block */
@@ -33022,23 +34192,23 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
}
} else if (x == DUK_ASC_LC_T) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
- duk_push_true(ctx);
+ duk_push_true(thr);
} else if (x == DUK_ASC_LC_F) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
- duk_push_false(ctx);
+ duk_push_false(thr);
} else if (x == DUK_ASC_LC_N) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
- duk_push_null(ctx);
+ duk_push_null(thr);
#if defined(DUK_USE_JX)
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
- duk_push_number(ctx, DUK_DOUBLE_INFINITY);
+ duk_push_number(thr, DUK_DOUBLE_INFINITY);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
duk__dec_pointer(js_ctx);
} else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
@@ -33068,65 +34238,65 @@ DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
* there is a reasonable limit on C recursion depth and hence object depth.
*/
DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h;
duk_uarridx_t i, arr_len;
DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr),
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
- duk_dup_top(ctx);
- duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */
+ duk_dup_top(thr);
+ duk_get_prop(thr, -3); /* -> [ ... holder name val ] */
- h = duk_get_hobject(ctx, -1);
+ h = duk_get_hobject(thr, -1);
if (h != NULL) {
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
- arr_len = (duk_uarridx_t) duk_get_length(ctx, -1);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, -1);
for (i = 0; i < arr_len; i++) {
/* [ ... holder name val ] */
DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
- (long) duk_get_top(ctx), (long) i, (long) arr_len,
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (long) i, (long) arr_len,
+ (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
- duk_dup_top(ctx);
- (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */
+ duk_dup_top(thr);
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */
duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -1, i);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_del_prop_index(thr, -1, i);
} else {
/* XXX: duk_xdef_prop_index_wec() would be more appropriate
* here but it currently makes some assumptions that might
* not hold (e.g. that previous property is not an accessor).
*/
- duk_put_prop_index(ctx, -2, i);
+ duk_put_prop_index(thr, -2, i);
}
}
} else {
/* [ ... holder name val ] */
- duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
- while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
+ duk_enum(thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
+ while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5),
- (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3),
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -5),
+ (duk_tval *) duk_get_tval(thr, -4), (duk_tval *) duk_get_tval(thr, -3),
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... holder name val enum obj_key ] */
- duk_dup_m3(ctx);
- duk_dup_m2(ctx);
+ duk_dup_m3(thr);
+ duk_dup_m2(thr);
/* [ ... holder name val enum obj_key val obj_key ] */
duk__dec_reviver_walk(js_ctx);
/* [ ... holder name val enum obj_key new_elem ] */
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop(ctx, -3);
+ if (duk_is_undefined(thr, -1)) {
+ duk_pop(thr);
+ duk_del_prop(thr, -3);
} else {
/* XXX: duk_xdef_prop_index_wec() would be more appropriate
* here but it currently makes some assumptions that might
@@ -33137,21 +34307,21 @@ DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
* does not happen normally, but a clever reviver can trigger
* that, see complex reviver case in: test-bug-json-parse-__proto__.js.
*/
- duk_put_prop(ctx, -4);
+ duk_put_prop(thr, -4);
}
}
- duk_pop(ctx); /* pop enum */
+ duk_pop(thr); /* pop enum */
}
}
/* [ ... holder name val ] */
- duk_dup(ctx, js_ctx->idx_reviver);
- duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */
- duk_call_method(ctx, 2); /* -> [ ... res ] */
+ duk_dup(thr, js_ctx->idx_reviver);
+ duk_insert(thr, -4); /* -> [ ... reviver holder name val ] */
+ duk_call_method(thr, 2); /* -> [ ... res ] */
DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1)));
}
/*
@@ -33221,7 +34391,7 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin
#if defined(DUK_USE_JX)
if (DUK_LIKELY(cp < 0x100UL)) {
- if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
+ if (DUK_UNLIKELY(js_ctx->flag_ext_custom != 0U)) {
tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
} else {
tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
@@ -33232,7 +34402,7 @@ DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uin
tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
} else {
#if defined(DUK_USE_JX)
- if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
+ if (DUK_LIKELY(js_ctx->flag_ext_custom != 0U)) {
tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
} else
#endif
@@ -33449,7 +34619,6 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st
*/
DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
duk_hthread *thr;
- duk_context *ctx;
duk_tval *tv;
duk_double_t d;
duk_small_int_t c;
@@ -33461,10 +34630,9 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
DUK_ASSERT(js_ctx != NULL);
thr = js_ctx->thr;
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
/* Caller must ensure 'tv' is indeed a double and not a fastint! */
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
d = DUK_TVAL_GET_DOUBLE(tv);
@@ -33481,15 +34649,15 @@ DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
*/
if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
(js_ctx->flag_ext_custom_or_compatible))) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_ZERO); /* '-0' */
} else
#endif /* DUK_USE_JX || DUK_USE_JC */
{
n2s_flags = 0;
/* [ ... number ] -> [ ... string ] */
- duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
+ duk_numconv_stringify(thr, 10 /*radix*/, 0 /*digits*/, n2s_flags);
}
- h_str = duk_known_hstring(ctx, -1);
+ h_str = duk_known_hstring(thr, -1);
DUK__EMIT_HSTR(js_ctx, h_str);
return;
}
@@ -33691,7 +34859,7 @@ DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuff
DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
/* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18,
- * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some spare.
+ * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some slack.
*
* Note that because the output buffer is reallocated from time to time,
* side effects (such as finalizers) affecting the buffer 'h' must be
@@ -33781,7 +34949,7 @@ DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj)
* directly related to indent depth.
*/
#if defined(DUK_USE_PREFER_SIZE)
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
DUK_ASSERT(js_ctx->h_gap != NULL);
DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
@@ -33791,7 +34959,7 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth
}
}
#else /* DUK_USE_PREFER_SIZE */
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
+DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
const duk_uint8_t *gap_data;
duk_size_t gap_len;
duk_size_t avail_bytes; /* bytes of indent available for copying */
@@ -33845,19 +35013,19 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth
/* 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_hthread *thr = js_ctx->thr;
duk_hobject *h_target;
duk_uint_fast32_t i, n;
- *entry_top = duk_get_top(ctx);
+ *entry_top = duk_get_top(thr);
- duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
+ duk_require_stack(thr, DUK_JSON_ENC_REQSTACK);
/* Loop check using a hybrid approach: a fixed-size visited[] array
* with overflow in a loop check object.
*/
- h_target = duk_known_hobject(ctx, -1); /* object or array */
+ h_target = duk_known_hobject(thr, -1); /* object or array */
n = js_ctx->recursion_depth;
if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
@@ -33866,37 +35034,37 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_
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_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
+ DUK_ERROR_TYPE(thr, 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_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_dup_top(thr); /* -> [ ... voidp voidp ] */
+ if (duk_has_prop(thr, js_ctx->idx_loop)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
}
- duk_push_true(ctx); /* -> [ ... voidp true ] */
- duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ duk_push_true(thr); /* -> [ ... voidp true ] */
+ duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
}
/* C recursion check. */
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT);
+ DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT);
}
js_ctx->recursion_depth++;
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)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, 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_idx_t *entry_top) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hobject *h_target;
/* C recursion check. */
@@ -33907,20 +35075,20 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_t
/* Loop check. */
- h_target = duk_known_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
+ h_target = duk_known_hobject(thr, *entry_top - 1); /* original target at entry_top - 1 */
if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
/* Previous entry was inside visited[], nothing to do. */
} else {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
+ duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
+ duk_del_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
}
/* Restore stack top after unbalanced code paths. */
- duk_set_top(ctx, *entry_top);
+ duk_set_top(thr, *entry_top);
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)));
+ (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
}
/* The JO(value) operation: encode object.
@@ -33928,7 +35096,7 @@ DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_t
* Stack policy: [ object ] -> [ object ].
*/
DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_hstring *h_key;
duk_idx_t entry_top;
duk_idx_t idx_obj;
@@ -33937,7 +35105,7 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
duk_uarridx_t arr_len, i;
duk_size_t prev_size;
- DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1)));
duk__enc_objarr_entry(js_ctx, &entry_top);
@@ -33947,14 +35115,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
idx_keys = js_ctx->idx_proplist;
} else {
/* XXX: would be nice to enumerate an object at specified index */
- duk_dup(ctx, idx_obj);
- (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
- idx_keys = duk_require_normalize_index(ctx, -1);
+ duk_dup(thr, idx_obj);
+ (void) duk_hobject_get_enumerated_keys(thr, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
+ idx_keys = duk_require_normalize_index(thr, -1);
/* leave stack unbalanced on purpose */
}
DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
- (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys)));
+ (long) idx_keys, (duk_tval *) duk_get_tval(thr, idx_keys)));
/* Steps 8-10 have been merged to avoid a "partial" variable. */
@@ -33966,16 +35134,16 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
* that it can be reallocated).
*/
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, idx_keys);
emitted = 0;
for (i = 0; i < arr_len; i++) {
- duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */
+ duk_get_prop_index(thr, idx_keys, i); /* -> [ ... key ] */
DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
- (duk_tval *) duk_get_tval(ctx, idx_obj),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, idx_obj),
+ (duk_tval *) duk_get_tval(thr, -1)));
- h_key = duk_known_hstring(ctx, -1);
+ h_key = duk_known_hstring(thr, -1);
DUK_ASSERT(h_key != NULL);
DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */
@@ -34009,14 +35177,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
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__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
duk__enc_objarr_exit(js_ctx, &entry_top);
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
}
/* The JA(value) operation: encode array.
@@ -34024,14 +35192,14 @@ DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
* Stack policy: [ array ] -> [ array ].
*/
DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
+ duk_hthread *thr = js_ctx->thr;
duk_idx_t entry_top;
duk_idx_t idx_arr;
duk_bool_t emitted;
duk_uarridx_t i, arr_len;
DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__enc_objarr_entry(js_ctx, &entry_top);
@@ -34041,11 +35209,11 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
+ arr_len = (duk_uarridx_t) duk_get_length(thr, idx_arr);
emitted = 0;
for (i = 0; i < arr_len; i++) {
DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_arr),
+ (duk_tval *) duk_get_tval(thr, idx_arr),
(long) i, (long) arr_len));
if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
@@ -34053,7 +35221,7 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
}
- (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) i); /* -> [ ... key ] */
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... key ] */
/* [ ... key ] */
@@ -34075,14 +35243,14 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
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__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
duk__enc_objarr_exit(js_ctx, &entry_top);
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
}
/* The Str(key, holder) operation.
@@ -34090,71 +35258,68 @@ DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
* Stack policy: [ ... key ] -> [ ... ]
*/
DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hthread *thr = (duk_hthread *) ctx;
+ duk_hthread *thr = js_ctx->thr;
duk_tval *tv;
duk_tval *tv_holder;
duk_tval *tv_key;
duk_small_int_t c;
DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
- (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder),
+ (duk_tval *) duk_get_tval(thr, -1)));
- DUK_UNREF(thr);
-
- tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder);
+ tv_holder = DUK_GET_TVAL_POSIDX(thr, idx_holder);
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
- tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */
(void) duk_hobject_getprop(thr, tv_holder, tv_key);
/* -> [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
/* Standard JSON checks for .toJSON() only for actual objects; for
* example, setting Number.prototype.toJSON and then serializing a
* number won't invoke the .toJSON() method. However, lightfuncs and
* plain buffers mimic objects so we check for their .toJSON() method.
*/
- if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT |
+ if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER)) {
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_JSON);
- if (duk_is_callable(ctx, -1)) { /* toJSON() can also be a lightfunc */
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_JSON);
+ if (duk_is_callable(thr, -1)) { /* toJSON() can also be a lightfunc */
DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
- /* XXX: duk_dup_unvalidated(ctx, -2) etc. */
- duk_dup_m2(ctx); /* -> [ ... key val toJSON val ] */
- duk_dup_m4(ctx); /* -> [ ... key val toJSON val key ] */
- duk_call_method(ctx, 1); /* -> [ ... key val val' ] */
- duk_remove_m2(ctx); /* -> [ ... key val' ] */
+ /* XXX: duk_dup_unvalidated(thr, -2) etc. */
+ duk_dup_m2(thr); /* -> [ ... key val toJSON val ] */
+ duk_dup_m4(thr); /* -> [ ... key val toJSON val key ] */
+ duk_call_method(thr, 1); /* -> [ ... key val val' ] */
+ duk_remove_m2(thr); /* -> [ ... key val' ] */
} else {
- duk_pop(ctx); /* -> [ ... key val ] */
+ duk_pop(thr); /* -> [ ... key val ] */
}
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
if (js_ctx->h_replacer) {
/* XXX: Here a "slice copy" would be useful. */
DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
- duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
- duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */
- duk_dup_m4(ctx); /* -> [ ... key val replacer holder key ] */
- duk_dup_m4(ctx); /* -> [ ... key val replacer holder key val ] */
- duk_call_method(ctx, 2); /* -> [ ... key val val' ] */
- duk_remove_m2(ctx); /* -> [ ... key val' ] */
+ duk_push_hobject(thr, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
+ duk_dup(thr, idx_holder); /* -> [ ... key val replacer holder ] */
+ duk_dup_m4(thr); /* -> [ ... key val replacer holder key ] */
+ duk_dup_m4(thr); /* -> [ ... key val replacer holder key val ] */
+ duk_call_method(thr, 2); /* -> [ ... key val val' ] */
+ duk_remove_m2(thr); /* -> [ ... key val' ] */
}
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h;
@@ -34179,19 +35344,19 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
switch (c) {
case DUK_HOBJECT_CLASS_NUMBER: {
DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
- duk_to_number_m1(ctx);
+ duk_to_number_m1(thr);
/* The coercion potentially invokes user .valueOf() and .toString()
* but can't result in a function value because ToPrimitive() would
* reject such a result: test-dev-json-stringify-coercion-1.js.
*/
- DUK_ASSERT(!duk_is_callable(ctx, -1));
+ DUK_ASSERT(!duk_is_callable(thr, -1));
break;
}
case DUK_HOBJECT_CLASS_STRING: {
DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
/* Same coercion behavior as for Number. */
- DUK_ASSERT(!duk_is_callable(ctx, -1));
+ DUK_ASSERT(!duk_is_callable(thr, -1));
break;
}
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -34199,8 +35364,8 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
#endif
case DUK_HOBJECT_CLASS_BOOLEAN: {
DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
- duk_remove_m2(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ duk_remove_m2(thr);
break;
}
default: {
@@ -34236,14 +35401,14 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
/* [ ... key val ] */
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
- if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
+ if (duk_check_type_mask(thr, -1, js_ctx->mask_for_undefined)) {
/* will result in undefined */
DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
goto pop2_undef;
}
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
switch (DUK_TVAL_GET_TAG(tv)) {
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
@@ -34311,7 +35476,7 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
/* Could implement a fastpath, but the fast path would need
* to handle realloc side effects correctly.
*/
- duk_to_object(ctx, -1);
+ duk_to_object(thr, -1);
duk__enc_object(js_ctx);
break;
}
@@ -34349,11 +35514,11 @@ DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_hold
#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
pop2_emitted:
#endif
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
+ duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
return 1; /* emitted */
pop2_undef:
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
+ duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
return 0; /* not emitted */
}
@@ -34482,7 +35647,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* it (though it's OK to abort the fast path).
*/
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
+ DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
DUK_DD(DUK_DDPRINT("fast path recursion limit"));
@@ -34514,7 +35679,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* 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_HOBJECT_IS_PROXY(obj)) {
DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
goto abort_fastpath;
}
@@ -34562,7 +35727,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
}
- c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
+ c_bit = (duk_uint32_t) DUK_HOBJECT_GET_CLASS_MASK(obj);
if (c_bit & c_object) {
/* All other object types. */
DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
@@ -34638,7 +35803,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
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__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
@@ -34685,9 +35850,9 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
* to support gappy arrays for all practical code.
*/
- h_tmp = duk_push_uint_to_hstring((duk_context *) js_ctx->thr, (duk_uint_t) i);
+ h_tmp = duk_push_uint_to_hstring(js_ctx->thr, (duk_uint_t) i);
has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
- duk_pop((duk_context *) js_ctx->thr);
+ duk_pop(js_ctx->thr);
if (has_inherited) {
DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
goto abort_fastpath;
@@ -34715,7 +35880,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
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__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
}
}
DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
@@ -34845,9 +36010,9 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
/* XXX: Stack discipline is annoying, could be changed in numconv. */
- duk_push_tval((duk_context *) js_ctx->thr, tv);
+ duk_push_tval(js_ctx->thr, tv);
duk__enc_double(js_ctx);
- duk_pop((duk_context *) js_ctx->thr);
+ duk_pop(js_ctx->thr);
#if 0
/* Could also rely on native sprintf(), but it will handle
@@ -34876,20 +36041,20 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
return 0; /* unreachable */
}
-DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx, void *udata) {
+DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) {
duk_json_enc_ctx *js_ctx;
duk_tval *tv;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(thr != NULL);
DUK_ASSERT(udata != NULL);
js_ctx = (duk_json_enc_ctx *) udata;
DUK_ASSERT(js_ctx != NULL);
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -1);
if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); /* Error message is ignored, so doesn't matter. */
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* Error message is ignored, so doesn't matter. */
}
return 0;
@@ -34901,16 +36066,15 @@ DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx, void *udata) {
*/
DUK_INTERNAL
-void duk_bi_json_parse_helper(duk_context *ctx,
+void duk_bi_json_parse_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_json_dec_ctx js_ctx_alloc;
duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
duk_hstring *h_text;
#if defined(DUK_USE_ASSERTIONS)
- duk_idx_t entry_top = duk_get_top(ctx);
+ duk_idx_t entry_top = duk_get_top(thr);
#endif
/* negative top-relative indices not allowed now */
@@ -34918,10 +36082,10 @@ void duk_bi_json_parse_helper(duk_context *ctx,
DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_reviver),
(unsigned long) flags,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
js_ctx->thr = thr;
@@ -34946,7 +36110,7 @@ void duk_bi_json_parse_helper(duk_context *ctx,
js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
#endif
- h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place; rejects Symbols */
+ h_text = duk_to_hstring(thr, idx_value); /* coerce in-place; rejects Symbols */
DUK_ASSERT(h_text != NULL);
/* JSON parsing code is allowed to read [p_start,p_end]: p_end is
@@ -34969,47 +36133,46 @@ void duk_bi_json_parse_helper(duk_context *ctx,
duk__dec_syntax_error(js_ctx);
}
- if (duk_is_callable(ctx, idx_reviver)) {
+ if (duk_is_callable(thr, idx_reviver)) {
DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
+ (duk_tval *) duk_get_tval(thr, idx_reviver)));
js_ctx->idx_reviver = idx_reviver;
- duk_push_object(ctx);
- duk_dup_m2(ctx); /* -> [ ... val root val ] */
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
+ duk_push_object(thr);
+ duk_dup_m2(thr); /* -> [ ... val root val ] */
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
+ duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
- duk_remove_m2(ctx); /* -> [ ... val' ] */
+ duk_remove_m2(thr); /* -> [ ... val' ] */
} else {
DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
+ (duk_tval *) duk_get_tval(thr, idx_reviver)));
}
/* Final result is at stack top. */
DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_reviver),
(unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (long) duk_get_top(thr)));
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
}
DUK_INTERNAL
-void duk_bi_json_stringify_helper(duk_context *ctx,
+void duk_bi_json_stringify_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_json_enc_ctx js_ctx_alloc;
duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
duk_hobject *h;
@@ -35022,13 +36185,13 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_replacer),
+ (duk_tval *) duk_get_tval(thr, idx_space),
(unsigned long) flags,
- (long) duk_get_top(ctx)));
+ (long) duk_get_top(thr)));
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
/*
* Context init
@@ -35110,7 +36273,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
- js_ctx->idx_loop = duk_push_bare_object(ctx);
+ js_ctx->idx_loop = duk_push_bare_object(thr);
DUK_ASSERT(js_ctx->idx_loop >= 0);
/* [ ... buf loop ] */
@@ -35119,7 +36282,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Process replacer/proplist (2nd argument to JSON.stringify)
*/
- h = duk_get_hobject(ctx, idx_replacer);
+ h = duk_get_hobject(thr, idx_replacer);
if (h != NULL) {
if (DUK_HOBJECT_IS_CALLABLE(h)) {
js_ctx->h_replacer = h;
@@ -35133,30 +36296,30 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
duk_uarridx_t plist_idx = 0;
duk_small_uint_t enum_flags;
- js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
+ js_ctx->idx_proplist = duk_push_array(thr); /* XXX: array internal? */
enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
- duk_enum(ctx, idx_replacer, enum_flags);
- while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
+ duk_enum(thr, idx_replacer, enum_flags);
+ while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) {
/* [ ... proplist enum_obj key val ] */
- if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
+ if (duk__enc_allow_into_proplist(duk_get_tval(thr, -1))) {
/* XXX: duplicates should be eliminated here */
DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_to_string(ctx, -1); /* extra coercion of strings is OK */
- duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_to_string(thr, -1); /* extra coercion of strings is OK */
+ duk_put_prop_index(thr, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
plist_idx++;
- duk_pop(ctx);
+ duk_pop(thr);
} else {
DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop_2(ctx);
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
+ duk_pop_2(thr);
}
}
- duk_pop(ctx); /* pop enum */
+ duk_pop(thr); /* pop enum */
/* [ ... proplist ] */
}
@@ -35168,17 +36331,17 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Process space (3rd argument to JSON.stringify)
*/
- h = duk_get_hobject(ctx, idx_space);
+ h = duk_get_hobject(thr, idx_space);
if (h != NULL) {
- int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
+ duk_small_uint_t c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
if (c == DUK_HOBJECT_CLASS_NUMBER) {
- duk_to_number(ctx, idx_space);
+ duk_to_number(thr, idx_space);
} else if (c == DUK_HOBJECT_CLASS_STRING) {
- duk_to_string(ctx, idx_space);
+ duk_to_string(thr, idx_space);
}
}
- if (duk_is_number(ctx, idx_space)) {
+ if (duk_is_number(thr, idx_space)) {
duk_small_int_t nspace;
/* spaces[] must be static to allow initializer with old compilers like BCC */
static const char spaces[10] = {
@@ -35188,16 +36351,16 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
}; /* XXX: helper */
/* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
- nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
+ nspace = (duk_small_int_t) duk_to_int_clamped(thr, idx_space, 0 /*minval*/, 10 /*maxval*/);
DUK_ASSERT(nspace >= 0 && nspace <= 10);
- duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
- js_ctx->h_gap = duk_known_hstring(ctx, -1);
+ duk_push_lstring(thr, spaces, (duk_size_t) nspace);
+ js_ctx->h_gap = duk_known_hstring(thr, -1);
DUK_ASSERT(js_ctx->h_gap != NULL);
- } else if (duk_is_string_notsymbol(ctx, idx_space)) {
- duk_dup(ctx, idx_space);
- duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
- js_ctx->h_gap = duk_known_hstring(ctx, -1);
+ } else if (duk_is_string_notsymbol(thr, idx_space)) {
+ duk_dup(thr, idx_space);
+ duk_substring(thr, -1, 0, 10); /* clamp to 10 chars */
+ js_ctx->h_gap = duk_known_hstring(thr, -1);
} else {
/* nop */
}
@@ -35242,7 +36405,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* limited loop detection).
*/
- duk_dup(ctx, idx_value);
+ duk_dup(thr, idx_value);
/* Must prevent finalizers which may have arbitrary side effects. */
prev_ms_base_flags = thr->heap->ms_base_flags;
@@ -35251,7 +36414,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
thr->heap->pf_prevent_count++; /* Prevent finalizers. */
DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
- pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/);
+ pcall_rc = duk_safe_call(thr, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/);
DUK_ASSERT(thr->heap->pf_prevent_count > 0);
thr->heap->pf_prevent_count--;
@@ -35278,22 +36441,22 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Create wrapper object and serialize
*/
- idx_holder = duk_push_object(ctx);
- duk_dup(ctx, idx_value);
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_EMPTY_STRING);
+ idx_holder = duk_push_object(thr);
+ duk_dup(thr, idx_value);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING);
DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
"proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
+ (duk_tval *) duk_get_tval(thr, 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_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* serialize the wrapper with empty string key */
- duk_push_hstring_empty(ctx);
+ duk_push_hstring_empty(thr);
/* [ ... buf loop (proplist) (gap) holder "" ] */
@@ -35302,7 +36465,7 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
/* Result is undefined. */
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
} else {
/* Convert buffer to result string. */
DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
@@ -35311,11 +36474,11 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
"proplist=%!T, gap=%!O, holder=%!T",
(unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
+ (duk_tval *) duk_get_tval(thr, 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_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
(duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, idx_holder)));
+ (duk_tval *) duk_get_tval(thr, idx_holder)));
/* The stack has a variable shape here, so force it to the
* desired one explicitly.
@@ -35324,19 +36487,19 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
replace_finished:
#endif
- duk_replace(ctx, entry_top);
- duk_set_top(ctx, entry_top + 1);
+ duk_replace(thr, entry_top);
+ duk_set_top(thr, entry_top + 1);
DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
"flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
+ (duk_tval *) duk_get_tval(thr, idx_value),
+ (duk_tval *) duk_get_tval(thr, idx_replacer),
+ (duk_tval *) duk_get_tval(thr, idx_space),
(unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (long) duk_get_top(thr)));
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
}
#if defined(DUK_USE_JSON_BUILTIN)
@@ -35345,16 +36508,16 @@ void duk_bi_json_stringify_helper(duk_context *ctx,
* Entry points
*/
-DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) {
- duk_bi_json_parse_helper(ctx,
+DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_hthread *thr) {
+ duk_bi_json_parse_helper(thr,
0 /*idx_value*/,
1 /*idx_replacer*/,
0 /*flags*/);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
- duk_bi_json_stringify_helper(ctx,
+DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_hthread *thr) {
+ duk_bi_json_stringify_helper(thr,
0 /*idx_value*/,
1 /*idx_replacer*/,
2 /*idx_space*/,
@@ -35399,8 +36562,8 @@ DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
typedef double (*duk__one_arg_func)(double);
typedef double (*duk__two_arg_func)(double, double);
-DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk__two_arg_func min_max) {
- duk_idx_t n = duk_get_top(ctx);
+DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk__two_arg_func min_max) {
+ duk_idx_t n = duk_get_top(thr);
duk_idx_t i;
duk_double_t res = initial;
duk_double_t t;
@@ -35417,7 +36580,7 @@ DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk
*/
for (i = 0; i < n; i++) {
- t = duk_to_number(ctx, i);
+ t = duk_to_number(thr, i);
if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
/* Note: not normalized, but duk_push_number() will normalize */
res = (duk_double_t) DUK_DOUBLE_NAN;
@@ -35426,7 +36589,7 @@ DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk
}
}
- duk_push_number(ctx, res);
+ duk_push_number(thr, res);
return 1;
}
@@ -35694,49 +36857,49 @@ DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
#endif
};
-DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
- duk_small_int_t fun_idx = duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_hthread *thr) {
+ duk_small_int_t fun_idx = duk_get_current_magic(thr);
duk__one_arg_func fun;
duk_double_t arg1;
DUK_ASSERT(fun_idx >= 0);
DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
- arg1 = duk_to_number(ctx, 0);
+ arg1 = duk_to_number(thr, 0);
fun = duk__one_arg_funcs[fun_idx];
- duk_push_number(ctx, (duk_double_t) fun((double) arg1));
+ duk_push_number(thr, (duk_double_t) fun((double) arg1));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
- duk_small_int_t fun_idx = duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_hthread *thr) {
+ duk_small_int_t fun_idx = duk_get_current_magic(thr);
duk__two_arg_func fun;
duk_double_t arg1;
duk_double_t arg2;
DUK_ASSERT(fun_idx >= 0);
DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
- arg1 = duk_to_number(ctx, 0); /* explicit ordered evaluation to match coercion semantics */
- arg2 = duk_to_number(ctx, 1);
+ arg1 = duk_to_number(thr, 0); /* explicit ordered evaluation to match coercion semantics */
+ arg2 = duk_to_number(thr, 1);
fun = duk__two_arg_funcs[fun_idx];
- duk_push_number(ctx, (duk_double_t) fun((double) arg1, (double) arg2));
+ duk_push_number(thr, (duk_double_t) fun((double) arg1, (double) arg2));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
- return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_hthread *thr) {
+ return duk__math_minmax(thr, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
- return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
+DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_hthread *thr) {
+ return duk__math_minmax(thr, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
}
-DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
- duk_push_number(ctx, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE((duk_hthread *) ctx));
+DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_hthread *thr) {
+ duk_push_number(thr, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr));
return 1;
}
#if defined(DUK_USE_ES6)
-DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_hthread *thr) {
/*
* E6 Section 20.2.2.18: Math.hypot
*
@@ -35756,13 +36919,13 @@ DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx) {
duk_double_t comp, prelim;
duk_double_t t;
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
/* Find the highest value. Also ToNumber() coerces. */
max = 0.0;
found_nan = 0;
for (i = 0; i < nargs; i++) {
- t = DUK_FABS(duk_to_number(ctx, i));
+ t = DUK_FABS(duk_to_number(thr, i));
if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) {
found_nan = 1;
} else {
@@ -35772,13 +36935,13 @@ DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx) {
/* Early return cases. */
if (max == DUK_DOUBLE_INFINITY) {
- duk_push_number(ctx, DUK_DOUBLE_INFINITY);
+ duk_push_number(thr, DUK_DOUBLE_INFINITY);
return 1;
} else if (found_nan) {
- duk_push_number(ctx, DUK_DOUBLE_NAN);
+ duk_push_number(thr, DUK_DOUBLE_NAN);
return 1;
} else if (max == 0.0) {
- duk_push_number(ctx, 0.0);
+ duk_push_number(thr, 0.0);
/* Otherwise we'd divide by zero. */
return 1;
}
@@ -35791,14 +36954,107 @@ DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx) {
sum = 0.0;
comp = 0.0;
for (i = 0; i < nargs; i++) {
- t = DUK_FABS(duk_get_number(ctx, i)) / max;
+ t = DUK_FABS(duk_get_number(thr, i)) / max;
summand = (t * t) - comp;
prelim = sum + summand;
comp = (prelim - sum) - summand;
sum = prelim;
}
- duk_push_number(ctx, (duk_double_t) DUK_SQRT(sum) * max);
+ duk_push_number(thr, (duk_double_t) DUK_SQRT(sum) * max);
+ return 1;
+}
+#endif /* DUK_USE_ES6 */
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_math_object_sign(duk_hthread *thr) {
+ duk_double_t d;
+
+ d = duk_to_number(thr, 0);
+ if (duk_double_is_nan(d)) {
+ DUK_ASSERT(duk_is_nan(thr, -1));
+ return 1; /* NaN input -> return NaN */
+ }
+ if (d == 0.0) {
+ /* Zero sign kept, i.e. -0 -> -0, +0 -> +0. */
+ return 1;
+ }
+ duk_push_int(thr, (d > 0.0 ? 1 : -1));
+ return 1;
+}
+#endif /* DUK_USE_ES6 */
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_math_object_clz32(duk_hthread *thr) {
+ duk_uint32_t x;
+ duk_small_uint_t i;
+
+#if defined(DUK_USE_PREFER_SIZE)
+ duk_uint32_t mask;
+
+ x = duk_to_uint32(thr, 0);
+ for (i = 0, mask = 0x80000000UL; mask != 0; mask >>= 1) {
+ if (x & mask) {
+ break;
+ }
+ i++;
+ }
+ DUK_ASSERT(i <= 32);
+ duk_push_uint(thr, i);
+ return 1;
+#else /* DUK_USE_PREFER_SIZE */
+ i = 0;
+ x = duk_to_uint32(thr, 0);
+ if (x & 0xffff0000UL) {
+ x >>= 16;
+ } else {
+ i += 16;
+ }
+ if (x & 0x0000ff00UL) {
+ x >>= 8;
+ } else {
+ i += 8;
+ }
+ if (x & 0x000000f0UL) {
+ x >>= 4;
+ } else {
+ i += 4;
+ }
+ if (x & 0x0000000cUL) {
+ x >>= 2;
+ } else {
+ i += 2;
+ }
+ if (x & 0x00000002UL) {
+ x >>= 1;
+ } else {
+ i += 1;
+ }
+ if (x & 0x00000001UL) {
+ ;
+ } else {
+ i += 1;
+ }
+ DUK_ASSERT(i <= 32);
+ duk_push_uint(thr, i);
+ return 1;
+#endif /* DUK_USE_PREFER_SIZE */
+}
+#endif /* DUK_USE_ES6 */
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_math_object_imul(duk_hthread *thr) {
+ duk_uint32_t x, y, z;
+
+ x = duk_to_uint32(thr, 0);
+ y = duk_to_uint32(thr, 1);
+ z = x * y;
+
+ /* While arguments are ToUint32() coerced and the multiplication
+ * is unsigned as such, the final result is curiously interpreted
+ * as a signed 32-bit value.
+ */
+ duk_push_i32(thr, (duk_int32_t) z);
return 1;
}
#endif /* DUK_USE_ES6 */
@@ -35812,41 +37068,38 @@ DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx) {
#if defined(DUK_USE_NUMBER_BUILTIN)
-DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_context *ctx) {
+DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) {
duk_hobject *h;
/* Number built-in accepts a plain number or a Number object (whose
* internal value is operated on). Other types cause TypeError.
*/
- duk_push_this(ctx);
- if (duk_is_number(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ duk_push_this(thr);
+ if (duk_is_number(thr, -1)) {
+ DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
goto done;
}
- h = duk_get_hobject(ctx, -1);
+ h = duk_get_hobject(thr, -1);
if (!h ||
(DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
- DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ERROR_TYPE((duk_hthread *) ctx, "number expected");
+ DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_ERROR_TYPE(thr, "number expected");
}
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
- duk_remove_m2(ctx);
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
+ duk_remove_m2(thr);
done:
- return duk_get_number(ctx, -1);
+ return duk_get_number(thr, -1);
}
-DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_hthread *thr) {
duk_idx_t nargs;
duk_hobject *h_this;
- DUK_UNREF(thr);
-
/*
* The Number constructor uses ToNumber(arg) for number coercion
* (coercing an undefined argument to NaN). However, if the
@@ -35854,15 +37107,15 @@ DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
* this, a vararg function is used.
*/
- nargs = duk_get_top(ctx);
+ nargs = duk_get_top(thr);
if (nargs == 0) {
- duk_push_int(ctx, 0);
+ duk_push_int(thr, 0);
}
- duk_to_number(ctx, 0);
- duk_set_top(ctx, 1);
- DUK_ASSERT_TOP(ctx, 1);
+ duk_to_number(thr, 0);
+ duk_set_top(thr, 1);
+ DUK_ASSERT_TOP(thr, 1);
- if (!duk_is_constructor_call(ctx)) {
+ if (!duk_is_constructor_call(thr)) {
return 1;
}
@@ -35880,50 +37133,50 @@ DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
*/
/* XXX: helper */
- duk_push_this(ctx);
- h_this = duk_known_hobject(ctx, -1);
+ duk_push_this(thr);
+ h_this = duk_known_hobject(thr, -1);
DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
- duk_dup_0(ctx); /* -> [ val obj val ] */
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup_0(thr); /* -> [ val obj val ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
return 0; /* no return value -> don't replace created value */
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx) {
- (void) duk__push_this_number_plain(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_hthread *thr) {
+ (void) duk__push_this_number_plain(thr);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_hthread *thr) {
duk_small_int_t radix;
duk_small_uint_t n2s_flags;
- (void) duk__push_this_number_plain(ctx);
- if (duk_is_undefined(ctx, 0)) {
+ (void) duk__push_this_number_plain(thr);
+ if (duk_is_undefined(thr, 0)) {
radix = 10;
} else {
- radix = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 2, 36);
+ radix = (duk_small_int_t) duk_to_int_check_range(thr, 0, 2, 36);
}
DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
n2s_flags = 0;
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
radix /*radix*/,
0 /*digits*/,
n2s_flags /*flags*/);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_hthread *thr) {
/* XXX: just use toString() for now; permitted although not recommended.
* nargs==1, so radix is passed to toString().
*/
- return duk_bi_number_prototype_to_string(ctx);
+ return duk_bi_number_prototype_to_string(thr);
}
/*
@@ -35932,14 +37185,14 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx
/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) {
duk_small_int_t frac_digits;
duk_double_t d;
duk_small_int_t c;
duk_small_uint_t n2s_flags;
- frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
- d = duk__push_this_number_plain(ctx);
+ frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
+ d = duk__push_this_number_plain(thr);
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
@@ -35953,53 +37206,53 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
DUK_N2S_FLAG_FRACTION_DIGITS;
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
10 /*radix*/,
frac_digits /*digits*/,
n2s_flags /*flags*/);
return 1;
use_to_string:
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, -1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_hthread *thr) {
duk_bool_t frac_undefined;
duk_small_int_t frac_digits;
duk_double_t d;
duk_small_int_t c;
duk_small_uint_t n2s_flags;
- d = duk__push_this_number_plain(ctx);
+ d = duk__push_this_number_plain(thr);
- frac_undefined = duk_is_undefined(ctx, 0);
- duk_to_int(ctx, 0); /* for side effects */
+ frac_undefined = duk_is_undefined(thr, 0);
+ duk_to_int(thr, 0); /* for side effects */
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
goto use_to_string;
}
- frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
+ frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
(frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
10 /*radix*/,
frac_digits + 1 /*leading digit + fractions*/,
n2s_flags /*flags*/);
return 1;
use_to_string:
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, -1);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
/* The specification has quite awkward order of coercion and
* checks for toPrecision(). The operations below are a bit
* reordered, within constraints of observable side effects.
@@ -36010,27 +37263,27 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
duk_small_int_t c;
duk_small_uint_t n2s_flags;
- DUK_ASSERT_TOP(ctx, 1);
+ DUK_ASSERT_TOP(thr, 1);
- d = duk__push_this_number_plain(ctx);
- if (duk_is_undefined(ctx, 0)) {
+ d = duk__push_this_number_plain(thr);
+ if (duk_is_undefined(thr, 0)) {
goto use_to_string;
}
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
- duk_to_int(ctx, 0); /* for side effects */
+ duk_to_int(thr, 0); /* for side effects */
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
goto use_to_string;
}
- prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21);
+ prec = (duk_small_int_t) duk_to_int_check_range(thr, 0, 1, 21);
n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
DUK_N2S_FLAG_NO_ZERO_PAD;
- duk_numconv_stringify(ctx,
+ duk_numconv_stringify(thr,
10 /*radix*/,
prec /*digits*/,
n2s_flags /*flags*/);
@@ -36041,8 +37294,8 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
* and +/- infinity (-> "Infinity", "-Infinity").
*/
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
+ DUK_ASSERT_TOP(thr, 2);
+ duk_to_string(thr, -1);
return 1;
}
@@ -36054,26 +37307,26 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
/* #include duk_internal.h -> already included */
/* Needed even when Object built-in disabled. */
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
- tv = DUK_HTHREAD_THIS_PTR((duk_hthread *) ctx);
+ tv = DUK_HTHREAD_THIS_PTR(thr);
/* XXX: This is not entirely correct anymore; in ES2015 the
* default lookup should use @@toStringTag to come up with
* e.g. [object Symbol].
*/
- duk_push_class_string_tval(ctx, tv);
+ duk_push_class_string_tval(thr, tv);
return 1;
}
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_hthread *thr) {
duk_uint_t arg_mask;
- arg_mask = duk_get_type_mask(ctx, 0);
+ arg_mask = duk_get_type_mask(thr, 0);
- if (!duk_is_constructor_call(ctx) && /* not a constructor call */
+ if (!duk_is_constructor_call(thr) && /* not a constructor call */
((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) { /* and argument not null or undefined */
- duk_to_object(ctx, 0);
+ duk_to_object(thr, 0);
return 1;
}
@@ -36093,11 +37346,11 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
* be checked for explicitly, but Object(obj) calls are
* not very common so opt for minimal footprint.
*/
- duk_to_object(ctx, 0);
+ duk_to_object(thr, 0);
return 1;
}
- (void) duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
@@ -36107,27 +37360,27 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_hthread *thr) {
duk_idx_t nargs;
duk_int_t idx;
- nargs = duk_get_top_require_min(ctx, 1 /*min_top*/);
+ nargs = duk_get_top_require_min(thr, 1 /*min_top*/);
- duk_to_object(ctx, 0);
+ duk_to_object(thr, 0);
for (idx = 1; idx < nargs; idx++) {
/* E7 19.1.2.1 (step 4a) */
- if (duk_is_null_or_undefined(ctx, idx)) {
+ if (duk_is_null_or_undefined(thr, idx)) {
continue;
}
/* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is
* convenient here.
*/
- duk_to_object(ctx, idx);
- duk_enum(ctx, idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
- while (duk_next(ctx, -1, 1 /*get_value*/)) {
+ duk_to_object(thr, idx);
+ duk_enum(thr, idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
+ while (duk_next(thr, -1, 1 /*get_value*/)) {
/* [ target ... enum key value ] */
- duk_put_prop(ctx, 0);
+ duk_put_prop(thr, 0);
/* [ target ... enum ] */
}
/* Could pop enumerator, but unnecessary because of duk_set_top()
@@ -36135,41 +37388,41 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx) {
*/
}
- duk_set_top(ctx, 1);
+ duk_set_top(thr, 1);
return 1;
}
#endif
#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 2);
- duk_push_boolean(ctx, duk_samevalue(ctx, 0, 1));
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 2);
+ duk_push_boolean(thr, duk_samevalue(thr, 0, 1));
return 1;
}
#endif
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) {
duk_hobject *proto;
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 2);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- duk_hbufobj_promote_plain(ctx, 0);
+ duk_hbufobj_promote_plain(thr, 0);
#endif
- proto = duk_require_hobject_accept_mask(ctx, 0, DUK_TYPE_MASK_NULL);
- DUK_ASSERT(proto != NULL || duk_is_null(ctx, 0));
+ proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL);
+ DUK_ASSERT(proto != NULL || duk_is_null(thr, 0));
- (void) duk_push_object_helper_proto(ctx,
+ (void) duk_push_object_helper_proto(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
proto);
- if (!duk_is_undefined(ctx, 1)) {
+ if (!duk_is_undefined(thr, 1)) {
/* [ O Properties obj ] */
- duk_replace(ctx, 0);
+ duk_replace(thr, 0);
/* [ obj Properties ] */
@@ -36177,7 +37430,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
* finish up.
*/
- return duk_bi_object_constructor_define_properties(ctx);
+ return duk_bi_object_constructor_define_properties(thr);
}
/* [ O Properties obj ] */
@@ -36187,7 +37440,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_hthread *thr) {
duk_small_uint_t pass;
duk_uint_t defprop_flags;
duk_hobject *obj;
@@ -36196,14 +37449,14 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *
duk_hobject *set;
/* Lightfunc and plain buffer handling by ToObject() coercion. */
- obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
DUK_ASSERT(obj != NULL);
- duk_to_object(ctx, 1); /* properties object */
+ duk_to_object(thr, 1); /* properties object */
DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
/*
* Two pass approach to processing the property descriptors.
@@ -36216,27 +37469,27 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *
*/
for (pass = 0; pass < 2; pass++) {
- duk_set_top(ctx, 2); /* -> [ hobject props ] */
- duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/);
+ duk_set_top(thr, 2); /* -> [ hobject props ] */
+ duk_enum(thr, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/);
for (;;) {
duk_hstring *key;
/* [ hobject props enum(props) ] */
- duk_set_top(ctx, 3);
+ duk_set_top(thr, 3);
- if (!duk_next(ctx, 2, 1 /*get_value*/)) {
+ if (!duk_next(thr, 2, 1 /*get_value*/)) {
break;
}
DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
/* [ hobject props enum(props) key desc ] */
- duk_hobject_prepare_property_descriptor(ctx,
+ duk_hobject_prepare_property_descriptor(thr,
4 /*idx_desc*/,
&defprop_flags,
&idx_value,
@@ -36250,10 +37503,10 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *
}
/* This allows symbols on purpose. */
- key = duk_known_hstring(ctx, 3);
+ key = duk_known_hstring(thr, 3);
DUK_ASSERT(key != NULL);
- duk_hobject_define_property_helper(ctx,
+ duk_hobject_define_property_helper(thr,
defprop_flags,
obj,
key,
@@ -36268,149 +37521,100 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *
* Return target object
*/
- duk_dup_0(ctx);
+ duk_dup_0(thr);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
- duk_bool_t is_freeze;
-
- DUK_ASSERT_TOP(ctx, 1);
-
- is_freeze = (duk_bool_t) duk_get_current_magic(ctx);
- if (duk_is_buffer(ctx, 0)) {
- /* Plain buffer: already sealed, but not frozen (and can't be frozen
- * because index properties can't be made non-writable.
- */
- if (is_freeze) {
- goto fail_cannot_freeze;
- }
- return 1;
- } else if (duk_is_lightfunc(ctx, 0)) {
- /* Lightfunc: already sealed and frozen, success. */
- return 1;
- }
-#if 0
- /* Seal/freeze are quite rare in practice so it'd be nice to get the
- * correct behavior simply via automatic promotion (at the cost of some
- * memory churn). However, the promoted objects don't behave the same,
- * e.g. promoted lightfuncs are extensible.
- */
- h = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
-#endif
-
- h = duk_get_hobject(ctx, 0);
- if (h == NULL) {
- /* ES2015 Sections 19.1.2.5, 19.1.2.17 */
- return 1;
- }
-
- if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) {
- /* Buffer objects cannot be frozen because there's no internal
- * support for making virtual array indices non-writable.
- */
- DUK_DD(DUK_DDPRINT("cannot freeze a buffer object"));
- goto fail_cannot_freeze;
- }
-
- duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 1);
- /* Sealed and frozen objects cannot gain any more properties,
- * so this is a good time to compact them.
- */
- duk_hobject_compact_props(thr, h);
+ duk_seal_freeze_raw(thr, 0, (duk_bool_t) duk_get_current_magic(thr) /*is_freeze*/);
return 1;
-
- fail_cannot_freeze:
- DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_hthread *thr) {
duk_hobject *h;
duk_bool_t is_frozen;
duk_uint_t mask;
- is_frozen = duk_get_current_magic(ctx);
- mask = duk_get_type_mask(ctx, 0);
+ is_frozen = (duk_bool_t) duk_get_current_magic(thr);
+ mask = duk_get_type_mask(thr, 0);
if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
DUK_ASSERT(is_frozen == 0 || is_frozen == 1);
- duk_push_boolean(ctx, (mask & DUK_TYPE_MASK_LIGHTFUNC) ?
+ duk_push_boolean(thr, (mask & DUK_TYPE_MASK_LIGHTFUNC) ?
1 : /* lightfunc always frozen and sealed */
(is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */
} else {
/* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object
* is considered to be already sealed and frozen.
*/
- h = duk_get_hobject(ctx, 0);
- duk_push_boolean(ctx, (h == NULL) ||
- duk_hobject_object_is_sealed_frozen_helper((duk_hthread *) ctx, h, is_frozen /*is_frozen*/));
+ h = duk_get_hobject(thr, 0);
+ duk_push_boolean(thr, (h == NULL) ||
+ duk_hobject_object_is_sealed_frozen_helper(thr, h, is_frozen /*is_frozen*/));
}
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 0);
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_TO_STRING);
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 0);
+ (void) duk_push_this_coercible_to_object(thr);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING);
#if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */
- duk_require_callable(ctx, 1);
+ duk_require_callable(thr, 1);
#endif
- duk_dup_0(ctx); /* -> [ O toString O ] */
- duk_call_method(ctx, 0); /* XXX: call method tail call? */
+ duk_dup_0(thr); /* -> [ O toString O ] */
+ duk_call_method(thr, 0); /* XXX: call method tail call? */
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_hthread *thr) {
/* For lightfuncs and plain buffers, returns Object() coerced. */
- (void) duk_push_this_coercible_to_object(ctx);
+ (void) duk_push_this_coercible_to_object(thr);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) {
duk_hobject *h_v;
duk_hobject *h_obj;
- DUK_ASSERT_TOP(ctx, 1);
+ DUK_ASSERT_TOP(thr, 1);
- h_v = duk_get_hobject(ctx, 0);
+ h_v = duk_get_hobject(thr, 0);
if (!h_v) {
- duk_push_false(ctx); /* XXX: tail call: return duk_push_false(ctx) */
+ duk_push_false(thr); /* XXX: tail call: return duk_push_false(thr) */
return 1;
}
- h_obj = duk_push_this_coercible_to_object(ctx);
+ h_obj = duk_push_this_coercible_to_object(thr);
DUK_ASSERT(h_obj != NULL);
/* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
* Prototype loops should cause an error to be thrown.
*/
- duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
+ duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
- return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_hthread *thr) {
+ return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, 0 /*required_desc_flags*/);
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
- return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_hthread *thr) {
+ return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
}
#endif /* DUK_USE_OBJECT_BUILTIN */
@@ -36420,31 +37624,30 @@ DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_contex
*
* http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
*/
-DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_hthread *thr) {
/*
* magic = 0: __proto__ getter
* magic = 1: Object.getPrototypeOf()
* magic = 2: Reflect.getPrototypeOf()
*/
- duk_hthread *thr = (duk_hthread *) ctx;
duk_hobject *h;
duk_hobject *proto;
duk_tval *tv;
duk_int_t magic;
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
if (magic == 0) {
- DUK_ASSERT_TOP(ctx, 0);
- duk_push_this_coercible_to_object(ctx);
+ DUK_ASSERT_TOP(thr, 0);
+ duk_push_this_coercible_to_object(thr);
}
- DUK_ASSERT(duk_get_top(ctx) >= 1);
+ DUK_ASSERT(duk_get_top(thr) >= 1);
if (magic < 2) {
/* ES2015 Section 19.1.2.9, step 1 */
- duk_to_object(ctx, 0);
+ duk_to_object(thr, 0);
}
- tv = DUK_GET_TVAL_POSIDX(ctx, 0);
+ tv = DUK_GET_TVAL_POSIDX(thr, 0);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_BUFFER:
@@ -36464,9 +37667,9 @@ DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
if (proto != NULL) {
- duk_push_hobject(ctx, proto);
+ duk_push_hobject(thr, proto);
} else {
- duk_push_null(ctx);
+ duk_push_null(thr);
}
return 1;
}
@@ -36479,14 +37682,13 @@ DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
* http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
* http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
*/
-DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) {
/*
* magic = 0: __proto__ setter
* magic = 1: Object.setPrototypeOf()
* magic = 2: Reflect.setPrototypeOf()
*/
- duk_hthread *thr = (duk_hthread *) ctx;
duk_hobject *h_obj;
duk_hobject *h_new_proto;
duk_hobject *h_curr;
@@ -36495,11 +37697,11 @@ DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
duk_int_t magic;
/* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
if (magic == 0) {
- duk_push_this_check_object_coercible(ctx);
- duk_insert(ctx, 0);
- if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
+ duk_push_this_check_object_coercible(thr);
+ duk_insert(thr, 0);
+ if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
return 0;
}
@@ -36509,19 +37711,19 @@ DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
ret_success = 0;
} else {
if (magic == 1) {
- duk_require_object_coercible(ctx, 0);
+ duk_require_object_coercible(thr, 0);
} else {
- duk_require_hobject_accept_mask(ctx, 0,
+ duk_require_hobject_accept_mask(thr, 0,
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER);
}
- duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
+ duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
}
- h_new_proto = duk_get_hobject(ctx, 1);
+ h_new_proto = duk_get_hobject(thr, 1);
/* h_new_proto may be NULL */
- mask = duk_get_type_mask(ctx, 0);
+ mask = duk_get_type_mask(thr, 0);
if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
duk_hobject *curr_proto;
curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ?
@@ -36532,7 +37734,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
}
goto fail_nonextensible;
}
- h_obj = duk_get_hobject(ctx, 0);
+ h_obj = duk_get_hobject(thr, 0);
if (h_obj == NULL) {
goto skip;
}
@@ -36557,9 +37759,9 @@ DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
/* fall thru */
skip:
- duk_set_top(ctx, 1);
+ duk_set_top(thr, 1);
if (magic == 2) {
- duk_push_true(ctx);
+ duk_push_true(thr);
}
return ret_success;
@@ -36568,14 +37770,14 @@ DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
if (magic != 2) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
} else {
- duk_push_false(ctx);
+ duk_push_false(thr);
return 1;
}
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *thr) {
/*
* magic = 0: Object.defineProperty()
* magic = 1: Reflect.defineProperty()
@@ -36587,34 +37789,34 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ct
duk_hobject *set;
duk_idx_t idx_value;
duk_uint_t defprop_flags;
- duk_int_t magic;
+ duk_small_uint_t magic;
duk_bool_t throw_flag;
duk_bool_t ret;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(thr != NULL);
DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
- (void *) ctx,
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
+ (void *) thr,
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1),
+ (duk_tval *) duk_get_tval(thr, 2)));
/* [ obj key desc ] */
- magic = duk_get_current_magic(ctx);
+ magic = (duk_small_uint_t) duk_get_current_magic(thr);
/* Lightfuncs are currently supported by coercing to a temporary
* Function object; changes will be allowed (the coerced value is
* extensible) but will be lost. Same for plain buffers.
*/
- obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
DUK_ASSERT(obj != NULL);
- key = duk_to_property_key_hstring(ctx, 1);
- (void) duk_require_hobject(ctx, 2);
+ key = duk_to_property_key_hstring(thr, 1);
+ (void) duk_require_hobject(thr, 2);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);
+ DUK_ASSERT(duk_get_hobject(thr, 2) != NULL);
/*
* Validate and convert argument property descriptor (an Ecmascript
@@ -36624,7 +37826,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ct
* Lightfunc set/get values are coerced to full Functions.
*/
- duk_hobject_prepare_property_descriptor(ctx,
+ duk_hobject_prepare_property_descriptor(thr,
2 /*idx_desc*/,
&defprop_flags,
&idx_value,
@@ -36635,9 +37837,9 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ct
* Use Object.defineProperty() helper for the actual operation.
*/
- DUK_ASSERT(magic == 0 || magic == 1);
- throw_flag = magic ^ 1;
- ret = duk_hobject_define_property_helper(ctx,
+ DUK_ASSERT(magic == 0U || magic == 1U);
+ throw_flag = magic ^ 1U;
+ ret = duk_hobject_define_property_helper(thr,
defprop_flags,
obj,
key,
@@ -36650,35 +37852,35 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ct
* they're popped automatically.
*/
- if (magic == 0) {
+ if (magic == 0U) {
/* Object.defineProperty(): return target object. */
- duk_push_hobject(ctx, obj);
+ duk_push_hobject(thr, obj);
} else {
/* Reflect.defineProperty(): return success/fail. */
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
}
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 2);
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 2);
/* ES2015 Section 19.1.2.6, step 1 */
- if (duk_get_current_magic(ctx) == 0) {
- duk_to_object(ctx, 0);
+ if (duk_get_current_magic(thr) == 0) {
+ duk_to_object(thr, 0);
}
/* [ obj key ] */
- duk_hobject_object_get_own_property_descriptor(ctx, -2);
+ duk_hobject_object_get_own_property_descriptor(thr, -2);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) {
/*
* magic = 0: Object.isExtensible()
* magic = 1: Reflect.isExtensible()
@@ -36686,16 +37888,16 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx)
duk_hobject *h;
- if (duk_get_current_magic(ctx) == 0) {
- h = duk_get_hobject(ctx, 0);
+ if (duk_get_current_magic(thr) == 0) {
+ h = duk_get_hobject(thr, 0);
} else {
/* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs
* and plain buffers here because they pretend to be objects.
*/
- h = duk_require_hobject_accept_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
}
- duk_push_boolean(ctx, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h));
+ duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h));
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
@@ -36731,8 +37933,7 @@ DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = {
DUK_ENUM_NO_PROXY_BEHAVIOR
};
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) {
duk_hobject *obj;
#if defined(DUK_USE_ES6_PROXY)
duk_hobject *h_proxy_target;
@@ -36742,18 +37943,17 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
duk_small_uint_t enum_flags;
duk_int_t magic;
- DUK_ASSERT_TOP(ctx, 1);
- DUK_UNREF(thr);
+ DUK_ASSERT_TOP(thr, 1);
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
if (magic == 3) {
/* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs
* and plain buffers pretend to be objects, so accept those too.
*/
- obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
} else {
/* ES2015: ToObject coerce. */
- obj = duk_to_hobject(ctx, 0);
+ obj = duk_to_hobject(thr, 0);
}
DUK_ASSERT(obj != NULL);
DUK_UNREF(obj);
@@ -36762,64 +37962,62 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
#if defined(DUK_USE_ES6_PROXY)
/* XXX: better sharing of code between proxy target call sites */
- if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
- obj,
+ if (DUK_LIKELY(!duk_hobject_proxy_check(obj,
&h_proxy_target,
&h_proxy_handler))) {
goto skip_proxy;
}
- duk_push_hobject(ctx, h_proxy_handler);
- if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
+ duk_push_hobject(thr, h_proxy_handler);
+ if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
/* Careful with reachability here: don't pop 'obj' before pushing
* proxy target.
*/
DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
- duk_pop_2(ctx);
- duk_push_hobject(ctx, h_proxy_target);
- duk_replace(ctx, 0);
- DUK_ASSERT_TOP(ctx, 1);
+ duk_pop_2(thr);
+ duk_push_hobject(thr, h_proxy_target);
+ duk_replace(thr, 0);
+ DUK_ASSERT_TOP(thr, 1);
goto skip_proxy;
}
/* [ obj handler trap ] */
- duk_insert(ctx, -2);
- duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */
- duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */
- h_trap_result = duk_require_hobject(ctx, -1);
+ duk_insert(thr, -2);
+ duk_push_hobject(thr, h_proxy_target); /* -> [ obj trap handler target ] */
+ duk_call_method(thr, 1 /*nargs*/); /* -> [ obj trap_result ] */
+ h_trap_result = duk_require_hobject(thr, -1);
DUK_UNREF(h_trap_result);
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
enum_flags = duk__object_keys_enum_flags[magic];
- duk_proxy_ownkeys_postprocess(ctx, h_proxy_target, enum_flags);
+ duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
return 1;
skip_proxy:
#endif /* DUK_USE_ES6_PROXY */
- DUK_ASSERT_TOP(ctx, 1);
- magic = duk_get_current_magic(ctx);
+ DUK_ASSERT_TOP(thr, 1);
+ magic = duk_get_current_magic(thr);
DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
enum_flags = duk__object_keys_enum_flags[magic];
- return duk_hobject_get_enumerated_keys(ctx, enum_flags);
+ return duk_hobject_get_enumerated_keys(thr, enum_flags);
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_hthread *thr) {
/*
* magic = 0: Object.preventExtensions()
* magic = 1: Reflect.preventExtensions()
*/
- duk_hthread *thr = (duk_hthread *) ctx;
duk_hobject *h;
duk_uint_t mask;
duk_int_t magic;
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
/* Silent success for lightfuncs and plain buffers always. */
mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER;
@@ -36834,11 +38032,11 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context
DUK_TYPE_MASK_POINTER;
}
- if (duk_check_type_mask(ctx, 0, mask)) {
+ if (duk_check_type_mask(thr, 0, mask)) {
/* Not an object, already non-extensible so always success. */
goto done;
}
- h = duk_require_hobject(ctx, 0);
+ h = duk_require_hobject(thr, 0);
DUK_ASSERT(h != NULL);
DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
@@ -36850,11 +38048,94 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context
done:
if (magic == 1) {
- duk_push_true(ctx);
+ duk_push_true(thr);
}
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
+
+/*
+ * __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__
+ */
+
+#if defined(DUK_USE_ES8)
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) {
+ duk_push_this(thr);
+ duk_insert(thr, 0);
+ duk_to_object(thr, 0);
+ duk_require_callable(thr, 2);
+
+ /* [ ToObject(this) key getter/setter ] */
+
+ /* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */
+ duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE |
+ DUK_DEFPROP_SET_CONFIGURABLE |
+ (duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER));
+ return 0;
+}
+DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) {
+ duk_uint_t sanity;
+
+ duk_push_this(thr);
+ duk_to_object(thr, -1);
+
+ /* XXX: Prototype walk (with sanity) should be a core property
+ * operation, could add a flag to e.g. duk_get_prop_desc().
+ */
+
+ /* ToPropertyKey() coercion is not needed, duk_get_prop_desc() does it. */
+ sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
+ while (!duk_is_undefined(thr, -1)) {
+ /* [ key obj ] */
+ duk_dup(thr, 0);
+ duk_get_prop_desc(thr, 1, 0 /*flags*/);
+ if (!duk_is_undefined(thr, -1)) {
+ duk_get_prop_stridx(thr, -1, (duk_get_current_magic(thr) != 0 ? DUK_STRIDX_SET : DUK_STRIDX_GET));
+ return 1;
+ }
+ duk_pop(thr);
+
+ if (DUK_UNLIKELY(sanity-- == 0)) {
+ DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
+ }
+
+ duk_get_prototype(thr, -1);
+ duk_remove(thr, -2);
+ }
+ return 1;
+}
+#endif /* DUK_USE_ES8 */
+/*
+ * High resolution time API (performance.now() et al)
+ *
+ * API specification: https://encoding.spec.whatwg.org/#ap://www.w3.org/TR/hr-time/
+ */
+
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_PERFORMANCE_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_performance_now(duk_hthread *thr) {
+ /* From API spec:
+ * The DOMHighResTimeStamp type is used to store a time value in
+ * milliseconds, measured relative from the time origin, global
+ * monotonic clock, or a time value that represents a duration
+ * between two DOMHighResTimeStamp's.
+ */
+ duk_push_number(thr, duk_time_get_monotonic_time(thr));
+ return 1;
+}
+
+#if 0 /* Missing until semantics decided. */
+DUK_INTERNAL duk_ret_t duk_bi_performance_timeorigin_getter(duk_hthread *thr) {
+ /* No decision yet how to handle timeOrigins, e.g. should one be
+ * initialized per heap, or per global object set. See
+ * https://www.w3.org/TR/hr-time/#time-origin.
+ */
+ duk_push_uint(thr, 0);
+ return 1;
+}
+#endif /* 0 */
+#endif /* DUK_USE_PERFORMANCE_BUILTIN */
/*
* Pointer built-ins
*/
@@ -36865,29 +38146,29 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_hthread *thr) {
/* XXX: this behavior is quite useless now; it would be nice to be able
* to create pointer values from e.g. numbers or strings. Numbers are
* problematic on 64-bit platforms though. Hex encoded strings?
*/
- if (duk_get_top(ctx) == 0) {
- duk_push_pointer(ctx, NULL);
+ if (duk_get_top(thr) == 0) {
+ duk_push_pointer(thr, NULL);
} else {
- duk_to_pointer(ctx, 0);
+ duk_to_pointer(thr, 0);
}
- DUK_ASSERT(duk_is_pointer(ctx, 0));
- duk_set_top(ctx, 1);
+ DUK_ASSERT(duk_is_pointer(thr, 0));
+ duk_set_top(thr, 1);
- if (duk_is_constructor_call(ctx)) {
- (void) duk_push_object_helper(ctx,
+ if (duk_is_constructor_call(thr)) {
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
DUK_BIDX_POINTER_PROTOTYPE);
/* Pointer object internal value is immutable */
- duk_dup_0(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup_0(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
}
/* Note: unbalanced stack on purpose */
@@ -36898,12 +38179,12 @@ DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
* toString(), valueOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr) {
duk_tval *tv;
- duk_small_int_t to_string = duk_get_current_magic(ctx);
+ duk_small_int_t to_string = duk_get_current_magic(thr);
- duk_push_this(ctx);
- tv = duk_require_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = duk_require_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_POINTER(tv)) {
@@ -36917,20 +38198,64 @@ DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx
goto type_error;
}
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
} else {
goto type_error;
}
if (to_string) {
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -1);
}
return 1;
type_error:
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/*
+ * Promise built-in
+ */
+
+/* #include duk_internal.h -> already included */
+
+#if defined(DUK_USE_PROMISE_BUILTIN)
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) {
+ DUK_ERROR_TYPE(thr, "unimplemented");
+ return 0;
+}
+
+#endif /* DUK_USE_PROMISE_BUILTIN */
+/*
* Proxy built-in (ES2015)
*/
@@ -36941,24 +38266,23 @@ DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx
* array of valid result keys (strings or symbols). TypeError for invalid
* values. Flags are shared with duk_enum().
*/
-DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h_proxy_target, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) {
duk_uarridx_t i, len, idx;
duk_propdesc desc;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(h_proxy_target != NULL);
- len = (duk_uarridx_t) duk_get_length(ctx, -1);
+ len = (duk_uarridx_t) duk_get_length(thr, -1);
idx = 0;
- duk_push_array(ctx);
+ duk_push_array(thr);
/* XXX: preallocated dense array, fill in directly */
for (i = 0; i < len; i++) {
duk_hstring *h;
/* [ obj trap_result res_arr ] */
- (void) duk_get_prop_index(ctx, -2, i);
- h = duk_get_hstring(ctx, -1);
+ (void) duk_get_prop_index(thr, -2, i);
+ h = duk_get_hstring(thr, -1);
if (h == NULL) {
DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
}
@@ -36968,38 +38292,38 @@ DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h
* so check enumerability always from target object
* descriptor.
*/
- if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(ctx, -1), &desc, 0 /*flags*/)) {
+ if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) {
if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
- DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
} else {
- DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
}
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
- DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) {
- DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
} else {
if (flags & DUK_ENUM_EXCLUDE_STRINGS) {
- DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
}
/* [ obj trap_result res_arr propname ] */
- duk_put_prop_index(ctx, -2, idx++);
+ duk_put_prop_index(thr, -2, idx++);
continue;
skip_key:
- duk_pop(ctx);
+ duk_pop(thr);
continue;
}
@@ -37018,66 +38342,12 @@ DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h
#endif /* DUK_USE_ES6_PROXY */
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
- duk_hobject *h_target;
- duk_hobject *h_handler;
-
- duk_require_constructor_call(ctx);
-
- /* Reject a proxy object as the target because it would need
- * special handler in property lookups. (ES2015 has no such restriction)
- */
- h_target = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
- DUK_ASSERT(h_target != NULL);
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) {
- goto fail_args;
- }
-
- /* Reject a proxy object as the handler because it would cause
- * potentially unbounded recursion. (ES2015 has no such restriction)
- *
- * There's little practical reason to use a lightfunc or a plain
- * buffer as the handler table: one could only provide traps via
- * their prototype objects (Function.prototype and ArrayBuffer.prototype).
- * Even so, as lightfuncs and plain buffers mimic their object
- * counterparts, they're promoted and accepted here.
- */
- h_handler = duk_require_hobject_promote_mask(ctx, 1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
- DUK_ASSERT(h_handler != NULL);
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) {
- goto fail_args;
- }
+DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 2); /* [ target handler ] */
- /* XXX: the returned value is exotic in ES2015, but we use a
- * simple object here with no prototype. Without a prototype,
- * ToPrimitive() coercion fails which is a bit confusing.
- * No callable check/handling in the current Proxy subset.
- */
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_FASTREFS |
- DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- NULL);
- DUK_ASSERT_TOP(ctx, 3);
-
- /* Make _Target and _Handler non-configurable and non-writable.
- * They can still be forcibly changed by C code (both user and
- * Duktape internal), but not by Ecmascript code.
- */
-
- /* Proxy target */
- duk_dup_0(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
-
- /* Proxy handler */
- duk_dup_1(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE);
-
- return 1; /* replacement handler */
-
- fail_args:
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ duk_require_constructor_call(thr);
+ duk_push_proxy(thr, 0 /*flags*/); /* [ target handler ] -> [ proxy ] */
+ return 1; /* replacement */
}
#endif /* DUK_USE_ES6_PROXY */
/*
@@ -37091,97 +38361,89 @@ DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
/* #include duk_internal.h -> already included */
#if defined(DUK_USE_REFLECT_BUILTIN)
-DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t ret;
- DUK_ASSERT_TOP(ctx, 2);
- (void) duk_require_hobject(ctx, 0);
- (void) duk_to_string(ctx, 1);
+ DUK_ASSERT_TOP(thr, 2);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
/* [ target key ] */
- thr = (duk_hthread *) ctx;
DUK_ASSERT(thr != NULL);
- tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
- tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/);
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_idx_t nargs;
- nargs = duk_get_top_require_min(ctx, 2 /*min_top*/);
- (void) duk_require_hobject(ctx, 0);
- (void) duk_to_string(ctx, 1);
- if (nargs >= 3 && !duk_strict_equals(ctx, 0, 2)) {
+ DUK_ASSERT(thr != NULL);
+ nargs = duk_get_top_require_min(thr, 2 /*min_top*/);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
+ if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) {
/* XXX: [[Get]] receiver currently unsupported */
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
/* [ target key receiver? ...? ] */
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
- tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
- tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
(void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t ret;
- DUK_ASSERT_TOP(ctx, 2);
- (void) duk_require_hobject(ctx, 0);
- (void) duk_to_string(ctx, 1);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_TOP(thr, 2);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
/* [ target key ] */
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
- tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
- tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
ret = duk_hobject_hasprop(thr, tv_obj, tv_key);
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_tval *tv_val;
duk_idx_t nargs;
duk_bool_t ret;
- nargs = duk_get_top_require_min(ctx, 3 /*min_top*/);
- (void) duk_require_hobject(ctx, 0);
- (void) duk_to_string(ctx, 1);
- if (nargs >= 4 && !duk_strict_equals(ctx, 0, 3)) {
+ DUK_ASSERT(thr != NULL);
+ nargs = duk_get_top_require_min(thr, 3 /*min_top*/);
+ (void) duk_require_hobject(thr, 0);
+ (void) duk_to_string(thr, 1);
+ if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) {
/* XXX: [[Set]] receiver currently unsupported */
- DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
+ DUK_ERROR_UNSUPPORTED(thr);
}
/* [ target key value receiver? ...? ] */
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
- tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
- tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
- tv_val = DUK_GET_TVAL_POSIDX(ctx, 2);
+ tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
+ tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
+ tv_val = DUK_GET_TVAL_POSIDX(thr, 2);
ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/);
- duk_push_boolean(ctx, ret);
+ duk_push_boolean(thr, ret);
return 1;
}
#endif /* DUK_USE_REFLECT_BUILTIN */
@@ -37193,35 +38455,34 @@ DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx) {
#if defined(DUK_USE_REGEXP_SUPPORT)
-DUK_LOCAL void duk__get_this_regexp(duk_context *ctx) {
+DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) {
duk_hobject *h;
- duk_push_this(ctx);
- h = duk_require_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_REGEXP);
+ duk_push_this(thr);
+ h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP);
DUK_ASSERT(h != NULL);
DUK_UNREF(h);
- duk_insert(ctx, 0); /* prepend regexp to valstack 0 index */
+ duk_insert(thr, 0); /* prepend regexp to valstack 0 index */
}
/* XXX: much to improve (code size) */
-DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_hthread *thr) {
duk_hobject *h_pattern;
- DUK_ASSERT_TOP(ctx, 2);
- h_pattern = duk_get_hobject(ctx, 0);
+ DUK_ASSERT_TOP(thr, 2);
+ h_pattern = duk_get_hobject(thr, 0);
- if (!duk_is_constructor_call(ctx) &&
+ if (!duk_is_constructor_call(thr) &&
h_pattern != NULL &&
DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
- duk_is_undefined(ctx, 1)) {
+ duk_is_undefined(thr, 1)) {
/* Called as a function, pattern has [[Class]] "RegExp" and
* flags is undefined -> return object as is.
*/
/* XXX: ES2015 has a NewTarget SameValue() check which is not
* yet implemented.
*/
- duk_dup_0(ctx);
+ duk_dup_0(thr);
return 1;
}
@@ -37231,40 +38492,40 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
if (h_pattern != NULL &&
DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
- duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_SOURCE);
- if (duk_is_undefined(ctx, 1)) {
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_SOURCE);
+ if (duk_is_undefined(thr, 1)) {
/* In ES5 one would need to read the flags individually;
* in ES2015 just read .flags.
*/
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_FLAGS);
+ duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
} else {
/* In ES2015 allowed; overrides argument RegExp flags. */
- duk_dup_1(ctx);
+ duk_dup_1(thr);
}
} else {
- if (duk_is_undefined(ctx, 0)) {
- duk_push_hstring_empty(ctx);
+ if (duk_is_undefined(thr, 0)) {
+ duk_push_hstring_empty(thr);
} else {
- duk_dup_0(ctx);
- duk_to_string(ctx, -1); /* Rejects Symbols. */
+ duk_dup_0(thr);
+ duk_to_string(thr, -1); /* Rejects Symbols. */
}
- if (duk_is_undefined(ctx, 1)) {
- duk_push_hstring_empty(ctx);
+ if (duk_is_undefined(thr, 1)) {
+ duk_push_hstring_empty(thr);
} else {
- duk_dup_1(ctx);
- duk_to_string(ctx, -1); /* Rejects Symbols. */
+ duk_dup_1(thr);
+ duk_to_string(thr, -1); /* Rejects Symbols. */
}
/* [ ... pattern flags ] */
}
DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... pattern flags ] (both uncoerced) */
- duk_to_string(ctx, -2);
- duk_to_string(ctx, -1);
+ duk_to_string(thr, -2);
+ duk_to_string(thr, -1);
duk_regexp_compile(thr);
/* [ ... bytecode escaped_source ] */
@@ -37276,46 +38537,46 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
- duk__get_this_regexp(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_hthread *thr) {
+ duk__get_this_regexp(thr);
/* [ regexp input ] */
- duk_regexp_match((duk_hthread *) ctx);
+ duk_regexp_match(thr);
/* [ result ] */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
- duk__get_this_regexp(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_hthread *thr) {
+ duk__get_this_regexp(thr);
/* [ regexp input ] */
/* result object is created and discarded; wasteful but saves code space */
- duk_regexp_match((duk_hthread *) ctx);
+ duk_regexp_match(thr);
/* [ result ] */
- duk_push_boolean(ctx, (duk_is_null(ctx, -1) ? 0 : 1));
+ duk_push_boolean(thr, (duk_is_null(thr, -1) ? 0 : 1));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) {
/* This must be generic in ES2015 and later. */
- DUK_ASSERT_TOP(ctx, 0);
- duk_push_this(ctx);
- duk_push_string(ctx, "/");
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
- duk_dup_m2(ctx); /* another "/" */
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_FLAGS);
- duk_concat(ctx, 4);
+ DUK_ASSERT_TOP(thr, 0);
+ duk_push_this(thr);
+ duk_push_string(thr, "/");
+ duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE);
+ duk_dup_m2(thr); /* another "/" */
+ duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
+ duk_concat(thr, 4);
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_hthread *thr) {
/* .flags is ES2015 but present even when ES2015 bindings are
* disabled because the constructor relies on it.
*/
@@ -37323,15 +38584,15 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx) {
duk_uint8_t *p = buf;
/* .flags is generic and works on any object. */
- duk_push_this(ctx);
- (void) duk_require_hobject(ctx, -1);
- if (duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL)) {
+ duk_push_this(thr);
+ (void) duk_require_hobject(thr, -1);
+ if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL)) {
*p++ = DUK_ASC_LC_G;
}
- if (duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_IGNORE_CASE, NULL)) {
+ if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_IGNORE_CASE, NULL)) {
*p++ = DUK_ASC_LC_I;
}
- if (duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_MULTILINE, NULL)) {
+ if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_MULTILINE, NULL)) {
*p++ = DUK_ASC_LC_M;
}
/* .unicode: to be added */
@@ -37339,30 +38600,29 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx) {
*p++ = DUK_ASC_NUL;
DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf));
- duk_push_string(ctx, (const char *) buf);
+ duk_push_string(thr, (const char *) buf);
return 1;
}
/* Shared helper for providing .source, .global, .multiline, etc getters. */
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) {
duk_hstring *h_bc;
- duk_small_int_t re_flags;
+ duk_small_uint_t re_flags;
duk_hobject *h;
duk_int_t magic;
- DUK_ASSERT_TOP(ctx, 0);
+ DUK_ASSERT_TOP(thr, 0);
- duk_push_this(ctx);
- h = duk_require_hobject(ctx, -1);
- magic = duk_get_current_magic(ctx);
+ duk_push_this(thr);
+ h = duk_require_hobject(thr, -1);
+ magic = duk_get_current_magic(thr);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) {
- duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_SOURCE);
- duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_BYTECODE);
- h_bc = duk_require_hstring(ctx, -1);
- re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_SOURCE);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_BYTECODE);
+ h_bc = duk_require_hstring(thr, -1);
+ re_flags = (duk_small_uint_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */
+ duk_pop(thr);
} else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) {
/* In ES2015 and ES2016 a TypeError would be thrown here.
* However, this had real world issues so ES2017 draft
@@ -37372,7 +38632,7 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx) {
if (magic != 16 /* .source */) {
return 0;
}
- duk_push_string(ctx, "(?:)"); /* .source handled by switch-case */
+ duk_push_string(thr, "(?:)"); /* .source handled by switch-case */
re_flags = 0;
} else {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
@@ -37382,15 +38642,15 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx) {
switch (magic) {
case 0: { /* global */
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL));
+ duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_GLOBAL));
break;
}
case 1: { /* ignoreCase */
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
+ duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
break;
}
case 2: { /* multiline */
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE));
+ duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_MULTILINE));
break;
}
#if 0
@@ -37399,7 +38659,7 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx) {
*/
case 3: /* sticky */
case 4: { /* unicode */
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
}
#endif
@@ -37438,19 +38698,19 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx) {
* Helpers
*/
-DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_context *ctx, duk_idx_t idx) {
+DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
- if (duk_get_class_number(ctx, idx) == DUK_HOBJECT_CLASS_REGEXP) {
- DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) {
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
}
- h = duk_to_hstring(ctx, idx);
+ h = duk_to_hstring(thr, idx);
DUK_ASSERT(h != NULL);
return h;
}
-DUK_LOCAL duk_int_t duk__str_search_shared(duk_context *ctx, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) {
+DUK_LOCAL duk_int_t duk__str_search_shared(duk_hthread *thr, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) {
duk_int_t cpos;
duk_int_t bpos;
const duk_uint8_t *p_start, *p_end, *p;
@@ -37472,7 +38732,7 @@ DUK_LOCAL duk_int_t duk__str_search_shared(duk_context *ctx, duk_hstring *h_this
}
DUK_ASSERT(q_blen > 0);
- bpos = (duk_int_t) duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h_this, (duk_uint32_t) cpos);
+ bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
p_start = DUK_HSTRING_GET_DATA(h_this);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
@@ -37528,7 +38788,7 @@ DUK_LOCAL duk_int_t duk__str_search_shared(duk_context *ctx, duk_hstring *h_this
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_hthread *thr) {
duk_hstring *h;
duk_uint_t flags;
@@ -37542,36 +38802,35 @@ DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
* current magic call sites.
*/
- if (duk_get_top(ctx) == 0) {
- duk_push_hstring_empty(ctx);
+ if (duk_get_top(thr) == 0) {
+ duk_push_hstring_empty(thr);
} else {
- h = duk_to_hstring_acceptsymbol(ctx, 0);
- if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx))) {
- duk_push_symbol_descriptive_string(ctx, h);
- duk_replace(ctx, 0);
+ h = duk_to_hstring_acceptsymbol(thr, 0);
+ if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(thr))) {
+ duk_push_symbol_descriptive_string(thr, h);
+ duk_replace(thr, 0);
}
}
- duk_to_string(ctx, 0); /* catches symbol argument for constructor call */
- DUK_ASSERT(duk_is_string(ctx, 0));
- duk_set_top(ctx, 1); /* Top may be 1 or larger. */
+ duk_to_string(thr, 0); /* catches symbol argument for constructor call */
+ DUK_ASSERT(duk_is_string(thr, 0));
+ duk_set_top(thr, 1); /* Top may be 1 or larger. */
- if (duk_is_constructor_call(ctx)) {
+ if (duk_is_constructor_call(thr)) {
/* String object internal value is immutable */
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
- duk_push_object_helper(ctx, flags, DUK_BIDX_STRING_PROTOTYPE);
- duk_dup_0(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_object_helper(thr, flags, DUK_BIDX_STRING_PROTOTYPE);
+ duk_dup_0(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
}
/* Note: unbalanced stack on purpose */
return 1;
}
-DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_context *ctx, duk_bool_t nonbmp) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_hthread *thr, duk_bool_t nonbmp) {
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
duk_idx_t i, n;
@@ -37583,10 +38842,10 @@ DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_context *ctx, duk_bool_t
* build a string from a duk_tval number sequence in one go?).
*/
- n = duk_get_top(ctx);
+ n = duk_get_top(thr);
bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, n); /* initial estimate for ASCII only codepoints */
+ DUK_BW_INIT_PUSHBUF(thr, bw, (duk_size_t) n); /* initial estimate for ASCII only codepoints */
for (i = 0; i < n; i++) {
/* XXX: could improve bufwriter handling to write multiple codepoints
@@ -37600,9 +38859,9 @@ DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_context *ctx, duk_bool_t
* the same.
*/
duk_int32_t i32 = 0;
- if (!duk_is_whole_get_int32(duk_to_number(ctx, i), &i32) ||
+ if (!duk_is_whole_get_int32(duk_to_number(thr, i), &i32) ||
i32 < 0 || i32 > 0x10ffffL) {
- DUK_DCERROR_RANGE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
DUK_ASSERT(i32 >= 0 && i32 <= 0x10ffffL);
cp = (duk_ucodepoint_t) i32;
@@ -37614,10 +38873,10 @@ DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_context *ctx, duk_bool_t
* non-BMP codepoints. Don't use CESU-8 because that'd create
* surrogate pairs.
*/
- cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
+ cp = (duk_ucodepoint_t) duk_to_uint32(thr, i);
DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
#else
- cp = (duk_ucodepoint_t) duk_to_uint16(ctx, i);
+ cp = (duk_ucodepoint_t) duk_to_uint16(thr, i);
DUK_ASSERT(cp >= 0 && cp <= 0x10ffffL);
DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
#endif
@@ -37625,17 +38884,17 @@ DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_context *ctx, duk_bool_t
}
DUK_BW_COMPACT(thr, bw);
- (void) duk_buffer_to_string(ctx, -1); /* Safe, extended UTF-8 or CESU-8 encoded. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 or CESU-8 encoded. */
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx) {
- return duk__construct_from_codepoints(ctx, 0 /*nonbmp*/);
+DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_hthread *thr) {
+ return duk__construct_from_codepoints(thr, 0 /*nonbmp*/);
}
#if defined(DUK_USE_ES6)
-DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx) {
- return duk__construct_from_codepoints(ctx, 1 /*nonbmp*/);
+DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_hthread *thr) {
+ return duk__construct_from_codepoints(thr, 1 /*nonbmp*/);
}
#endif
@@ -37643,11 +38902,11 @@ DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ct
* toString(), valueOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
- duk_push_this(ctx);
- tv = duk_require_tval(ctx, -1);
+ duk_push_this(thr);
+ tv = duk_require_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_STRING(tv)) {
@@ -37661,37 +38920,36 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
goto type_error;
}
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_string(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
+ DUK_ASSERT(duk_is_string(thr, -1));
} else {
goto type_error;
}
- (void) duk_require_hstring_notsymbol(ctx, -1); /* Reject symbols (and wrapped symbols). */
+ (void) duk_require_hstring_notsymbol(thr, -1); /* Reject symbols (and wrapped symbols). */
return 1;
type_error:
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/*
* Character and charcode access
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) {
duk_int_t pos;
/* XXX: faster implementation */
- (void) duk_push_this_coercible_to_string(ctx);
- pos = duk_to_int(ctx, 0);
- duk_substring(ctx, -1, pos, pos + 1);
+ (void) duk_push_this_coercible_to_string(thr);
+ pos = duk_to_int(thr, 0);
+ duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) (pos + 1));
return 1;
}
/* Magic: 0=charCodeAt, 1=codePointAt */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_hthread *thr) {
duk_int_t pos;
duk_hstring *h;
duk_bool_t clamped;
@@ -37700,20 +38958,20 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
/* XXX: faster implementation */
- DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(ctx, 0)));
+ DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(thr, 0)));
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
- pos = duk_to_int_clamped_raw(ctx,
+ pos = duk_to_int_clamped_raw(thr,
0 /*index*/,
0 /*min(incl)*/,
(duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
&clamped /*out_clamped*/);
#if defined(DUK_USE_ES6)
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
#else
- DUK_ASSERT(duk_get_current_magic(ctx) == 0);
+ DUK_ASSERT(duk_get_current_magic(thr) == 0);
magic = 0;
#endif
if (clamped) {
@@ -37723,10 +38981,11 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
if (magic != 0) {
return 0;
}
- duk_push_nan(ctx);
+ duk_push_nan(thr);
} else {
- cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, pos, (duk_bool_t) magic /*surrogate_aware*/);
- duk_push_u32(ctx, cp);
+ DUK_ASSERT(pos >= 0);
+ cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) pos, (duk_bool_t) magic /*surrogate_aware*/);
+ duk_push_u32(thr, cp);
}
return 1;
}
@@ -37739,22 +38998,22 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
* different algorithms so that footprint would be reduced?
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_hthread *thr) {
duk_hstring *h;
duk_int_t start_pos, end_pos;
duk_int_t len;
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
/* [ start end str ] */
- start_pos = duk_to_int_clamped(ctx, 0, 0, len);
- if (duk_is_undefined(ctx, 1)) {
+ start_pos = duk_to_int_clamped(thr, 0, 0, len);
+ if (duk_is_undefined(thr, 1)) {
end_pos = len;
} else {
- end_pos = duk_to_int_clamped(ctx, 1, 0, len);
+ end_pos = duk_to_int_clamped(thr, 1, 0, len);
}
DUK_ASSERT(start_pos >= 0 && start_pos <= len);
DUK_ASSERT(end_pos >= 0 && end_pos <= len);
@@ -37767,12 +39026,12 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
DUK_ASSERT(end_pos >= start_pos);
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
+ duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
return 1;
}
#if defined(DUK_USE_SECTION_B)
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_hthread *thr) {
duk_hstring *h;
duk_int_t start_pos, end_pos;
duk_int_t len;
@@ -37781,8 +39040,8 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
* specification will happily coerce undefined and null to strings
* ("undefined" and "null").
*/
- duk_push_this(ctx);
- h = duk_to_hstring_m1(ctx); /* Reject Symbols. */
+ duk_push_this(thr);
+ h = duk_to_hstring_m1(thr); /* Reject Symbols. */
DUK_ASSERT(h != NULL);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
@@ -37794,47 +39053,47 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
*/
/* combines steps 2 and 5; -len ensures max() not needed for step 5 */
- start_pos = duk_to_int_clamped(ctx, 0, -len, len);
+ start_pos = duk_to_int_clamped(thr, 0, -len, len);
if (start_pos < 0) {
start_pos = len + start_pos;
}
DUK_ASSERT(start_pos >= 0 && start_pos <= len);
/* combines steps 3, 6; step 7 is not needed */
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
end_pos = len;
} else {
DUK_ASSERT(start_pos <= len);
- end_pos = start_pos + duk_to_int_clamped(ctx, 1, 0, len - start_pos);
+ end_pos = start_pos + duk_to_int_clamped(thr, 1, 0, len - start_pos);
}
DUK_ASSERT(start_pos >= 0 && start_pos <= len);
DUK_ASSERT(end_pos >= 0 && end_pos <= len);
DUK_ASSERT(end_pos >= start_pos);
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
+ duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
return 1;
}
#endif /* DUK_USE_SECTION_B */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_hthread *thr) {
duk_hstring *h;
duk_int_t start_pos, end_pos;
duk_int_t len;
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
/* [ start end str ] */
- start_pos = duk_to_int_clamped(ctx, 0, -len, len);
+ start_pos = duk_to_int_clamped(thr, 0, -len, len);
if (start_pos < 0) {
start_pos = len + start_pos;
}
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
end_pos = len;
} else {
- end_pos = duk_to_int_clamped(ctx, 1, -len, len);
+ end_pos = duk_to_int_clamped(thr, 1, -len, len);
if (end_pos < 0) {
end_pos = len + end_pos;
}
@@ -37848,7 +39107,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
DUK_ASSERT(end_pos >= start_pos);
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
+ duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
return 1;
}
@@ -37856,11 +39115,10 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
* Case conversion
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_int_t uppercase = duk_get_current_magic(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_hthread *thr) {
+ duk_small_int_t uppercase = duk_get_current_magic(thr);
- (void) duk_push_this_coercible_to_string(ctx);
+ (void) duk_push_this_coercible_to_string(thr);
duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
return 1;
}
@@ -37869,33 +39127,33 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx)
* indexOf() and lastIndexOf()
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_hthread *thr) {
duk_hstring *h_this;
duk_hstring *h_search;
duk_int_t clen_this;
duk_int_t cpos;
- duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */
+ duk_small_uint_t is_lastindexof = (duk_small_uint_t) duk_get_current_magic(thr); /* 0=indexOf, 1=lastIndexOf */
- h_this = duk_push_this_coercible_to_string(ctx);
+ h_this = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h_this != NULL);
clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
- h_search = duk_to_hstring(ctx, 0);
+ h_search = duk_to_hstring(thr, 0);
DUK_ASSERT(h_search != NULL);
- duk_to_number(ctx, 1);
- if (duk_is_nan(ctx, 1) && is_lastindexof) {
+ duk_to_number(thr, 1);
+ if (duk_is_nan(thr, 1) && is_lastindexof) {
/* indexOf: NaN should cause pos to be zero.
* lastIndexOf: NaN should cause pos to be +Infinity
* (and later be clamped to len).
*/
cpos = clen_this;
} else {
- cpos = duk_to_int_clamped(ctx, 1, 0, clen_this);
+ cpos = duk_to_int_clamped(thr, 1, 0, clen_this);
}
- cpos = duk__str_search_shared(ctx, h_this, h_search, cpos, is_lastindexof /*backwards*/);
- duk_push_int(ctx, cpos);
+ cpos = duk__str_search_shared(thr, h_this, h_search, cpos, is_lastindexof /*backwards*/);
+ duk_push_int(thr, cpos);
return 1;
}
@@ -37914,8 +39172,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx)
* - API call to get_prop and to_boolean
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) {
duk_hstring *h_input;
duk_hstring *h_match;
duk_hstring *h_search;
@@ -37935,14 +39192,14 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */
duk_size_t tmp_sz;
- DUK_ASSERT_TOP(ctx, 2);
- h_input = duk_push_this_coercible_to_string(ctx);
+ DUK_ASSERT_TOP(thr, 2);
+ h_input = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
/* stack[0] = search value
* stack[1] = replace value
@@ -37950,29 +39207,29 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* stack[3] = result buffer
*/
- h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
+ h_re = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP);
if (h_re) {
#if defined(DUK_USE_REGEXP_SUPPORT)
is_regexp = 1;
- is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
+ is_global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
if (is_global) {
/* start match from beginning */
- duk_push_int(ctx, 0);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
}
#else /* DUK_USE_REGEXP_SUPPORT */
DUK_DCERROR_UNSUPPORTED(thr);
#endif /* DUK_USE_REGEXP_SUPPORT */
} else {
- duk_to_string(ctx, 0); /* rejects symbols */
+ duk_to_string(thr, 0); /* rejects symbols */
#if defined(DUK_USE_REGEXP_SUPPORT)
is_regexp = 0;
is_global = 0;
#endif
}
- if (duk_is_function(ctx, 1)) {
+ if (duk_is_function(thr, 1)) {
is_repl_func = 1;
r_start = NULL;
r_end = NULL;
@@ -37980,7 +39237,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
duk_hstring *h_repl;
is_repl_func = 0;
- h_repl = duk_to_hstring(ctx, 1); /* reject symbols */
+ h_repl = duk_to_hstring(thr, 1); /* reject symbols */
DUK_ASSERT(h_repl != NULL);
r_start = DUK_HSTRING_GET_DATA(h_repl);
r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
@@ -38012,27 +39269,27 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* are made? See: test-bi-string-proto-replace.js for discussion.
*/
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
- duk_dup_0(ctx);
- duk_dup_2(ctx);
+ duk_dup_0(thr);
+ duk_dup_2(thr);
duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
+ if (!duk_is_object(thr, -1)) {
+ duk_pop(thr);
break;
}
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_start_coff = duk_get_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ match_start_coff = duk_get_uint(thr, -1);
+ duk_pop(thr);
- duk_get_prop_index(ctx, -1, 0);
- DUK_ASSERT(duk_is_string(ctx, -1));
- h_match = duk_known_hstring(ctx, -1);
- duk_pop(ctx); /* h_match is borrowed, remains reachable through match_obj */
+ duk_get_prop_index(thr, -1, 0);
+ DUK_ASSERT(duk_is_string(thr, -1));
+ h_match = duk_known_hstring(thr, -1);
+ duk_pop(thr); /* h_match is borrowed, remains reachable through match_obj */
if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
/* This should be equivalent to match() algorithm step 8.f.iii.2:
@@ -38040,17 +39297,17 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
*/
duk_uint32_t last_index;
- duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
- last_index = (duk_uint32_t) duk_get_uint(ctx, -1);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ last_index = (duk_uint32_t) duk_get_uint(thr, -1);
DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
(long) last_index, (long) (last_index + 1)));
- duk_pop(ctx);
- duk_push_int(ctx, last_index + 1);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
+ duk_pop(thr);
+ duk_push_uint(thr, (duk_uint_t) (last_index + 1));
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
}
- DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX); /* string limits */
- match_caps = (duk_int_t) duk_get_length(ctx, -1);
+ DUK_ASSERT(duk_get_length(thr, -1) <= DUK_INT_MAX); /* string limits */
+ match_caps = (duk_int_t) duk_get_length(thr, -1);
} else {
#else /* DUK_USE_REGEXP_SUPPORT */
{ /* unconditionally */
@@ -38067,7 +39324,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start;
- h_search = duk_known_hstring(ctx, 0);
+ h_search = duk_known_hstring(thr, 0);
q_start = DUK_HSTRING_GET_DATA(h_search);
q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
@@ -38078,8 +39335,8 @@ 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((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
- duk_dup_0(ctx);
- h_match = duk_known_hstring(ctx, -1);
+ duk_dup_0(thr);
+ h_match = duk_known_hstring(thr, -1);
#if defined(DUK_USE_REGEXP_SUPPORT)
match_caps = 0;
#endif
@@ -38105,7 +39362,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* stack[4] = regexp match OR match string
*/
- match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
+ match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
@@ -38118,36 +39375,36 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
/* regexp res_obj is at index 4 */
- duk_dup_1(ctx);
- idx_args = duk_get_top(ctx);
+ duk_dup_1(thr);
+ idx_args = duk_get_top(thr);
#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
duk_int_t idx;
- duk_require_stack(ctx, match_caps + 2);
+ duk_require_stack(thr, match_caps + 2);
for (idx = 0; idx < match_caps; idx++) {
/* match followed by capture(s) */
- duk_get_prop_index(ctx, 4, idx);
+ duk_get_prop_index(thr, 4, (duk_uarridx_t) idx);
}
} else {
#else /* DUK_USE_REGEXP_SUPPORT */
{ /* unconditionally */
#endif /* DUK_USE_REGEXP_SUPPORT */
/* match == search string, by definition */
- duk_dup_0(ctx);
+ duk_dup_0(thr);
}
- duk_push_int(ctx, match_start_coff);
- duk_dup_2(ctx);
+ duk_push_uint(thr, (duk_uint_t) match_start_coff);
+ duk_dup_2(thr);
/* [ ... replacer match [captures] match_char_offset input ] */
- duk_call(ctx, duk_get_top(ctx) - idx_args);
- h_repl = duk_to_hstring_m1(ctx); /* -> [ ... repl_value ] */
+ duk_call(thr, duk_get_top(thr) - idx_args);
+ h_repl = duk_to_hstring_m1(thr); /* -> [ ... repl_value ] */
DUK_ASSERT(h_repl != NULL);
DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
- duk_pop(ctx); /* repl_value */
+ duk_pop(thr); /* repl_value */
} else {
r = r_start;
@@ -38163,7 +39420,8 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
if (ch1 != DUK_ASC_DOLLAR) {
goto repl_write;
}
- left = r_end - r;
+ DUK_ASSERT(r <= r_end);
+ left = (duk_size_t) (r_end - r);
if (left <= 0) {
goto repl_write;
@@ -38193,9 +39451,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* match codepoint encodings would have different lengths.
*/
/* XXX: charlen computed here, and also in char2byte helper. */
- match_end_boff = duk_heap_strcache_offset_char2byte(thr,
- h_input,
- match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match));
+ match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr,
+ h_input,
+ match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match));
tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
@@ -38234,17 +39492,17 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */
/* regexp res_obj is at offset 4 */
- duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum);
- if (duk_is_string(ctx, -1)) {
+ duk_get_prop_index(thr, 4, (duk_uarridx_t) capnum);
+ if (duk_is_string(thr, -1)) {
duk_hstring *h_tmp_str;
- h_tmp_str = duk_known_hstring(ctx, -1);
+ h_tmp_str = duk_known_hstring(thr, -1);
DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
} else {
/* undefined -> skip (replaced with empty) */
}
- duk_pop(ctx);
+ duk_pop(thr);
r += capadv;
continue;
} else {
@@ -38264,7 +39522,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
} /* while repl */
} /* if (is_repl_func) */
- duk_pop(ctx); /* pop regexp res_obj or match string */
+ duk_pop(thr); /* pop regexp res_obj or match string */
#if defined(DUK_USE_REGEXP_SUPPORT)
if (!is_global) {
@@ -38279,9 +39537,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
DUK_BW_COMPACT(thr, bw);
- (void) duk_buffer_to_string(ctx, -1); /* Safe if inputs are safe. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
return 1;
}
@@ -38293,8 +39551,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
* used so compiler doesn't complain).
*/
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) {
duk_hstring *h_input;
duk_hstring *h_sep;
duk_uint32_t limit;
@@ -38307,17 +39564,15 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
duk_uint32_t match_start_boff, match_start_coff;
duk_uint32_t match_end_boff, match_end_coff;
- DUK_UNREF(thr);
-
- h_input = duk_push_this_coercible_to_string(ctx);
+ h_input = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h_input != NULL);
- duk_push_array(ctx);
+ duk_push_array(thr);
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
limit = 0xffffffffUL;
} else {
- limit = duk_to_uint32(ctx, 1);
+ limit = duk_to_uint32(thr, 1);
}
if (limit == 0) {
@@ -38330,27 +39585,27 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
* which will use global-style matching even when the RegExp itself is non-global.
*/
- if (duk_is_undefined(ctx, 0)) {
+ if (duk_is_undefined(thr, 0)) {
/* The spec algorithm first does "R = ToString(separator)" before checking
* whether separator is undefined. Since this is side effect free, we can
* skip the ToString() here.
*/
- duk_dup_2(ctx);
- duk_put_prop_index(ctx, 3, 0);
+ duk_dup_2(thr);
+ duk_put_prop_index(thr, 3, 0);
return 1;
- } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
+ } else if (duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
#if defined(DUK_USE_REGEXP_SUPPORT)
- duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
- duk_dup_0(ctx);
- duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
- duk_replace(ctx, 0);
+ duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
+ duk_dup_0(thr);
+ duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */
+ duk_replace(thr, 0);
/* lastIndex is initialized to zero by new RegExp() */
is_regexp = 1;
#else
DUK_DCERROR_UNSUPPORTED(thr);
#endif
} else {
- duk_to_string(ctx, 0);
+ duk_to_string(thr, 0);
#if defined(DUK_USE_REGEXP_SUPPORT)
is_regexp = 0;
#endif
@@ -38375,42 +39630,42 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
* special variant which forces global-like behavior for matching.
*/
- DUK_ASSERT_TOP(ctx, 4);
+ DUK_ASSERT_TOP(thr, 4);
#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
- duk_dup_0(ctx);
- duk_dup_2(ctx);
+ duk_dup_0(thr);
+ duk_dup_2(thr);
duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
+ if (!duk_is_object(thr, -1)) {
+ duk_pop(thr);
break;
}
matched = 1;
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_start_coff = duk_get_int(ctx, -1);
- match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ match_start_coff = duk_get_uint(thr, -1);
+ match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
+ duk_pop(thr);
if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
/* don't allow an empty match at the end of the string */
- duk_pop(ctx);
+ duk_pop(thr);
break;
}
- duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_end_coff = duk_get_int(ctx, -1);
- match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ match_end_coff = duk_get_uint(thr, -1);
+ match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
+ duk_pop(thr);
/* empty match -> bump and continue */
if (prev_match_end_boff == match_end_boff) {
- duk_push_int(ctx, match_end_coff + 1);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
- duk_pop(ctx);
+ duk_push_uint(thr, (duk_uint_t) (match_end_coff + 1));
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ duk_pop(thr);
continue;
}
} else {
@@ -38425,7 +39680,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start + prev_match_end_boff;
- h_sep = duk_known_hstring(ctx, 0); /* symbol already rejected above */
+ h_sep = duk_known_hstring(thr, 0); /* symbol already rejected above */
q_start = DUK_HSTRING_GET_DATA(h_sep);
q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
@@ -38502,10 +39757,10 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
(long) match_end_boff, (long) match_end_coff,
(long) prev_match_end_boff, (long) prev_match_end_coff));
- duk_push_lstring(ctx,
+ duk_push_lstring(thr,
(const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
(duk_size_t) (match_start_boff - prev_match_end_boff));
- duk_put_prop_index(ctx, 3, arr_idx);
+ duk_put_prop_index(thr, 3, arr_idx);
arr_idx++;
if (arr_idx >= limit) {
goto hit_limit;
@@ -38515,18 +39770,18 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
if (is_regexp) {
duk_size_t i, len;
- len = duk_get_length(ctx, 4);
+ len = duk_get_length(thr, 4);
for (i = 1; i < len; i++) {
DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */
- duk_get_prop_index(ctx, 4, (duk_uarridx_t) i);
- duk_put_prop_index(ctx, 3, arr_idx);
+ duk_get_prop_index(thr, 4, (duk_uarridx_t) i);
+ duk_put_prop_index(thr, 3, arr_idx);
arr_idx++;
if (arr_idx >= limit) {
goto hit_limit;
}
}
- duk_pop(ctx);
+ duk_pop(thr);
/* lastIndex already set up for next match */
} else {
#else /* DUK_USE_REGEXP_SUPPORT */
@@ -38551,10 +39806,10 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
* b) empty input and no (zero size) match found (step 11)
*/
- duk_push_lstring(ctx,
+ duk_push_lstring(thr,
(const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
(duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
- duk_put_prop_index(ctx, 3, arr_idx);
+ duk_put_prop_index(thr, 3, arr_idx);
/* No arr_idx update or limit check */
}
@@ -38563,7 +39818,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
hit_limit:
#if defined(DUK_USE_REGEXP_SUPPORT)
if (is_regexp) {
- duk_pop(ctx);
+ duk_pop(thr);
}
#endif
@@ -38575,7 +39830,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
*/
#if defined(DUK_USE_REGEXP_SUPPORT)
-DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t idx, duk_bool_t force_new) {
+DUK_LOCAL void duk__to_regexp_helper(duk_hthread *thr, duk_idx_t idx, duk_bool_t force_new) {
duk_hobject *h;
/* Shared helper for match() steps 3-4, search() steps 3-4. */
@@ -38586,24 +39841,22 @@ DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t idx, duk_bool_t
goto do_new;
}
- h = duk_get_hobject_with_class(ctx, idx, DUK_HOBJECT_CLASS_REGEXP);
+ h = duk_get_hobject_with_class(thr, idx, DUK_HOBJECT_CLASS_REGEXP);
if (!h) {
goto do_new;
}
return;
do_new:
- duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
- duk_dup(ctx, idx);
- duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
- duk_replace(ctx, idx);
+ duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
+ duk_dup(thr, idx);
+ duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */
+ duk_replace(thr, idx);
}
#endif /* DUK_USE_REGEXP_SUPPORT */
#if defined(DUK_USE_REGEXP_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_hthread *thr) {
/* Easiest way to implement the search required by the specification
* is to do a RegExp test() with lastIndex forced to zero. To avoid
* side effects on the argument, "clone" the RegExp if a RegExp was
@@ -38614,9 +39867,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
* equivalent effect.
*/
- DUK_ASSERT_TOP(ctx, 1);
- (void) duk_push_this_coercible_to_string(ctx); /* at index 1 */
- duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);
+ DUK_ASSERT_TOP(thr, 1);
+ (void) duk_push_this_coercible_to_string(thr); /* at index 1 */
+ duk__to_regexp_helper(thr, 0 /*index*/, 1 /*force_new*/);
/* stack[0] = regexp
* stack[1] = string
@@ -38626,34 +39879,33 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
* configurable and may have been changed.
*/
- duk_dup_0(ctx);
- duk_dup_1(ctx); /* [ ... re_obj input ] */
+ duk_dup_0(thr);
+ duk_dup_1(thr); /* [ ... re_obj input ] */
duk_regexp_match(thr); /* -> [ ... res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_push_int(ctx, -1);
+ if (!duk_is_object(thr, -1)) {
+ duk_push_int(thr, -1);
return 1;
}
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
return 1;
}
#endif /* DUK_USE_REGEXP_SUPPORT */
#if defined(DUK_USE_REGEXP_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_hthread *thr) {
duk_bool_t global;
duk_int_t prev_last_index;
duk_int_t this_index;
duk_int_t arr_idx;
- DUK_ASSERT_TOP(ctx, 1);
- (void) duk_push_this_coercible_to_string(ctx);
- duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/);
- global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
- DUK_ASSERT_TOP(ctx, 2);
+ DUK_ASSERT_TOP(thr, 1);
+ (void) duk_push_this_coercible_to_string(thr);
+ duk__to_regexp_helper(thr, 0 /*index*/, 0 /*force_new*/);
+ global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
+ DUK_ASSERT_TOP(thr, 2);
/* stack[0] = regexp
* stack[1] = string
@@ -38668,9 +39920,9 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
/* [ regexp string ] */
- duk_push_int(ctx, 0);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
- duk_push_array(ctx);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ duk_push_array(thr);
/* [ regexp string res_arr ] */
@@ -38678,61 +39930,61 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
arr_idx = 0;
for (;;) {
- DUK_ASSERT_TOP(ctx, 3);
+ DUK_ASSERT_TOP(thr, 3);
- duk_dup_0(ctx);
- duk_dup_1(ctx);
+ duk_dup_0(thr);
+ duk_dup_1(thr);
duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
+ if (!duk_is_object(thr, -1)) {
+ duk_pop(thr);
break;
}
- duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- this_index = duk_get_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ this_index = duk_get_int(thr, -1);
+ duk_pop(thr);
if (this_index == prev_last_index) {
this_index++;
- duk_push_int(ctx, this_index);
- duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
+ duk_push_int(thr, this_index);
+ duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
}
prev_last_index = this_index;
- duk_get_prop_index(ctx, -1, 0); /* match string */
- duk_put_prop_index(ctx, 2, arr_idx);
+ duk_get_prop_index(thr, -1, 0); /* match string */
+ duk_put_prop_index(thr, 2, (duk_uarridx_t) arr_idx);
arr_idx++;
- duk_pop(ctx); /* res_obj */
+ duk_pop(thr); /* res_obj */
}
if (arr_idx == 0) {
- duk_push_null(ctx);
+ duk_push_null(thr);
}
return 1; /* return 'res_arr' or 'null' */
}
#endif /* DUK_USE_REGEXP_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_hthread *thr) {
/* duk_concat() coerces arguments with ToString() in correct order */
- (void) duk_push_this_coercible_to_string(ctx);
- duk_insert(ctx, 0); /* this is relatively expensive */
- duk_concat(ctx, duk_get_top(ctx));
+ (void) duk_push_this_coercible_to_string(thr);
+ duk_insert(thr, 0); /* this is relatively expensive */
+ duk_concat(thr, duk_get_top(thr));
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 0);
- (void) duk_push_this_coercible_to_string(ctx);
- duk_trim(ctx, 0);
- DUK_ASSERT_TOP(ctx, 1);
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_hthread *thr) {
+ DUK_ASSERT_TOP(thr, 0);
+ (void) duk_push_this_coercible_to_string(thr);
+ duk_trim(thr, 0);
+ DUK_ASSERT_TOP(thr, 1);
return 1;
}
#if defined(DUK_USE_ES6)
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
duk_hstring *h_input;
duk_size_t input_blen;
duk_size_t result_len;
@@ -38747,8 +39999,8 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx) {
duk_uint8_t *p_end;
#endif
- DUK_ASSERT_TOP(ctx, 1);
- h_input = duk_push_this_coercible_to_string(ctx);
+ DUK_ASSERT_TOP(thr, 1);
+ h_input = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h_input != NULL);
input_blen = DUK_HSTRING_GET_BYTELEN(h_input);
@@ -38758,11 +40010,11 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx) {
* because duk_get_int() clamps it to DUK_INT_MIN which gets rejected
* as a negative value (regardless of input string length).
*/
- d = duk_to_number(ctx, 0);
+ d = duk_to_number(thr, 0);
if (duk_double_is_posinf(d)) {
goto fail_range;
}
- count_signed = duk_get_int(ctx, 0);
+ count_signed = duk_get_int(thr, 0);
if (count_signed < 0) {
goto fail_range;
}
@@ -38775,7 +40027,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx) {
}
/* Temporary fixed buffer, later converted to string. */
- buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, result_len);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len);
src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
#if defined(DUK_USE_PREFER_SIZE)
@@ -38821,15 +40073,15 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx) {
* intern table (they are not in heap_allocated).
*/
- duk_buffer_to_string(ctx, -1); /* Safe if input is safe. */
+ duk_buffer_to_string(thr, -1); /* Safe if input is safe. */
return 1;
fail_range:
- DUK_DCERROR_RANGE_INVALID_ARGS((duk_hthread *) ctx);
+ DUK_DCERROR_RANGE_INVALID_ARGS(thr);
}
#endif /* DUK_USE_ES6 */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr) {
duk_hstring *h1;
duk_hstring *h2;
duk_size_t h1_len, h2_len, prefix_len;
@@ -38848,10 +40100,10 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx)
/* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
- h1 = duk_push_this_coercible_to_string(ctx);
+ h1 = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h1 != NULL);
- h2 = duk_to_hstring(ctx, 0);
+ h2 = duk_to_hstring(thr, 0);
DUK_ASSERT(h2 != NULL);
h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
@@ -38883,12 +40135,12 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx)
goto done;
done:
- duk_push_int(ctx, (duk_int_t) ret);
+ duk_push_int(thr, (duk_int_t) ret);
return 1;
}
#if defined(DUK_USE_ES6)
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *thr) {
duk_int_t magic;
duk_hstring *h;
duk_hstring *h_search;
@@ -38896,18 +40148,18 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *
const duk_uint8_t *p_cmp_start;
duk_bool_t result;
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
- h_search = duk__str_tostring_notregexp(ctx, 0);
+ h_search = duk__str_tostring_notregexp(thr, 0);
DUK_ASSERT(h_search != NULL);
- magic = duk_get_current_magic(ctx);
+ magic = duk_get_current_magic(thr);
p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
blen_search = DUK_HSTRING_GET_BYTELEN(h_search);
- if (duk_is_undefined(ctx, 1)) {
+ if (duk_is_undefined(thr, 1)) {
if (magic) {
p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search;
} else {
@@ -38919,7 +40171,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
- pos = duk_to_int_clamped(ctx, 1, 0, len);
+ pos = duk_to_int_clamped(thr, 1, 0, len);
DUK_ASSERT(pos >= 0 && pos <= len);
if (magic) {
@@ -38927,7 +40179,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *
}
DUK_ASSERT(pos >= 0 && pos <= len);
- p_cmp_start += duk_heap_strcache_offset_char2byte((duk_hthread *) ctx, h, pos);
+ p_cmp_start += duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) pos);
}
/* The main comparison can be done using a memcmp() rather than
@@ -38939,7 +40191,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *
result = 0;
if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) &&
- p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) {
+ (duk_size_t) (p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) {
if (DUK_MEMCMP((const void *) p_cmp_start,
(const void *) DUK_HSTRING_GET_DATA(h_search),
(size_t) blen_search) == 0) {
@@ -38947,30 +40199,30 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *
}
}
- duk_push_boolean(ctx, result);
+ duk_push_boolean(thr, result);
return 1;
}
#endif /* DUK_USE_ES6 */
#if defined(DUK_USE_ES6)
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_hthread *thr) {
duk_hstring *h;
duk_hstring *h_search;
duk_int_t len;
duk_int_t pos;
- h = duk_push_this_coercible_to_string(ctx);
+ h = duk_push_this_coercible_to_string(thr);
DUK_ASSERT(h != NULL);
- h_search = duk__str_tostring_notregexp(ctx, 0);
+ h_search = duk__str_tostring_notregexp(thr, 0);
DUK_ASSERT(h_search != NULL);
len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
- pos = duk_to_int_clamped(ctx, 1, 0, len);
+ pos = duk_to_int_clamped(thr, 1, 0, len);
DUK_ASSERT(pos >= 0 && pos <= len);
- pos = duk__str_search_shared(ctx, h, h_search, pos, 0 /*backwards*/);
- duk_push_boolean(ctx, pos >= 0);
+ pos = duk__str_search_shared(thr, h, h_search, pos, 0 /*backwards*/);
+ duk_push_boolean(thr, pos >= 0);
return 1;
}
#endif /* DUK_USE_ES6 */
@@ -38987,18 +40239,15 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx) {
* Constructor
*/
-DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx) {
- duk_hthread *thr;
+DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) {
const duk_uint8_t *desc;
duk_size_t len;
duk_uint8_t *buf;
duk_uint8_t *p;
duk_int_t magic;
- thr = (duk_hthread *) ctx;
-
- magic = duk_get_current_magic(ctx);
- if (duk_is_undefined(ctx, 0) && (magic == 0)) {
+ magic = duk_get_current_magic(thr);
+ if (duk_is_undefined(thr, 0) && (magic == 0)) {
/* Symbol() accepts undefined and empty string, but they are
* treated differently.
*/
@@ -39006,7 +40255,7 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx) {
len = 0;
} else {
/* Symbol.for() coerces undefined to 'undefined' */
- desc = (const duk_uint8_t *) duk_to_lstring(ctx, 0, &len);
+ desc = (const duk_uint8_t *) duk_to_lstring(thr, 0, &len);
}
/* Maximum symbol data length:
@@ -39016,7 +40265,7 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx) {
* +17 autogenerated unique suffix: 'ffffffff-ffffffff' is longest
* +1 0xff after unique suffix for symbols with undefined description
*/
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, 1 + len + 1 + 17 + 1);
+ buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1);
p = buf + 1;
DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */
DUK_MEMCPY((void *) p, (const void *) desc, len);
@@ -39045,12 +40294,12 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx) {
buf[0] = 0x80;
}
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
- DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(ctx, -1)));
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
+ DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(thr, -1)));
return 1;
}
-DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_context *ctx, duk_tval *tv_arg) {
+DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_hthread *thr, duk_tval *tv_arg) {
duk_tval *tv;
duk_tval tv_val;
duk_hobject *h_obj;
@@ -39058,15 +40307,15 @@ DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_context *ctx, duk_tval *tv_arg
DUK_ASSERT(tv_arg != NULL);
- /* XXX: add internal helper: duk_auto_unbox_tval(ctx, tv, mask); */
- /* XXX: add internal helper: duk_auto_unbox(ctx, tv, idx); */
+ /* XXX: add internal helper: duk_auto_unbox_tval(thr, tv, mask); */
+ /* XXX: add internal helper: duk_auto_unbox(thr, tv, idx); */
tv = tv_arg;
if (DUK_TVAL_IS_OBJECT(tv)) {
h_obj = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h_obj != NULL);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) {
- if (!duk_hobject_get_internal_value(((duk_hthread *) ctx)->heap, h_obj, &tv_val)) {
+ if (!duk_hobject_get_internal_value(thr->heap, h_obj, &tv_val)) {
return NULL;
}
tv = &tv_val;
@@ -39089,32 +40338,32 @@ DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_context *ctx, duk_tval *tv_arg
return h_str;
}
-DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_hthread *thr) {
duk_hstring *h_str;
- h_str = duk__auto_unbox_symbol(ctx, DUK_HTHREAD_THIS_PTR((duk_hthread *) ctx));
+ h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
if (h_str == NULL) {
return DUK_RET_TYPE_ERROR;
}
- if (duk_get_current_magic(ctx) == 0) {
+ if (duk_get_current_magic(thr) == 0) {
/* .toString() */
- duk_push_symbol_descriptive_string(ctx, h_str);
+ duk_push_symbol_descriptive_string(thr, h_str);
} else {
/* .valueOf() */
- duk_push_hstring(ctx, h_str);
+ duk_push_hstring(thr, h_str);
}
return 1;
}
-DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_hthread *thr) {
duk_hstring *h;
const duk_uint8_t *p;
/* Argument must be a symbol but not checked here. The initial byte
* check will catch non-symbol strings.
*/
- h = duk_require_hstring(ctx, 0);
+ h = duk_require_hstring(thr, 0);
DUK_ASSERT(h != NULL);
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
@@ -39125,9 +40374,9 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_context *ctx) {
*/
if (p[0] == 0x80) {
/* Global symbol, return its key (bytes just after the initial byte). */
- duk_push_lstring(ctx, (const char *) (p + 1), DUK_HSTRING_GET_BYTELEN(h) - 1);
+ duk_push_lstring(thr, (const char *) (p + 1), (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h) - 1));
return 1;
- } else if (p[0] == 0x81 || p[0] == 0xff) {
+ } else if (p[0] == 0x81 || p[0] == 0x82 || p[0] == 0xff) {
/* Local symbol or hidden symbol, return undefined. */
return 0;
}
@@ -39136,14 +40385,14 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_context *ctx) {
return DUK_RET_TYPE_ERROR;
}
-DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_hthread *thr) {
duk_hstring *h_str;
- h_str = duk__auto_unbox_symbol(ctx, DUK_HTHREAD_THIS_PTR((duk_hthread *) ctx));
+ h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
if (h_str == NULL) {
return DUK_RET_TYPE_ERROR;
}
- duk_push_hstring(ctx, h_str);
+ duk_push_hstring(thr, h_str);
return 1;
}
@@ -39159,7 +40408,7 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_context *ctx) {
*/
#if defined(DUK_USE_COROUTINE_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) {
duk_hthread *new_thr;
duk_hobject *func;
@@ -39168,18 +40417,18 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
* Resume will reject such functions in any case.
*/
/* XXX: need a duk_require_func_promote_lfunc() */
- func = duk_require_hobject_promote_lfunc(ctx, 0);
+ func = duk_require_hobject_promote_lfunc(thr, 0);
DUK_ASSERT(func != NULL);
- duk_require_callable(ctx, 0);
+ duk_require_callable(thr, 0);
- duk_push_thread(ctx);
- new_thr = (duk_hthread *) duk_known_hobject(ctx, -1);
+ duk_push_thread(thr);
+ new_thr = (duk_hthread *) duk_known_hobject(thr, -1);
new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
/* push initial function call to new thread stack; this is
* picked up by resume().
*/
- duk_push_hobject((duk_context *) new_thr, func);
+ duk_push_hobject(new_thr, func);
return 1; /* return thread */
}
@@ -39201,23 +40450,23 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
*/
#if defined(DUK_USE_COROUTINE_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
+DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_hthread *thr_resume;
duk_hobject *caller_func;
- duk_small_int_t is_error;
+ duk_small_uint_t is_error;
DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1),
+ (duk_tval *) duk_get_tval(thr, 2)));
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->heap->curr_thread == thr);
- thr_resume = duk_require_hthread(ctx, 0);
- is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
- duk_set_top(ctx, 2);
+ thr_resume = duk_require_hthread(thr, 0);
+ is_error = (duk_small_uint_t) duk_to_boolean(thr, 2);
+ duk_set_top(thr, 2);
/* [ thread value ] */
@@ -39230,11 +40479,12 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
goto state_error;
}
DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr - 1) != NULL); /* caller */
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
- caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1);
+ caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
goto state_error;
@@ -39274,13 +40524,13 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
goto state_error;
}
- duk_push_tval(ctx, DUK_GET_TVAL_NEGIDX((duk_context *) thr_resume, -1));
- duk_resolve_nonbound_function(ctx);
- h_fun = duk_require_hobject(ctx, -1); /* reject lightfuncs on purpose */
+ duk_push_tval(thr, DUK_GET_TVAL_NEGIDX(thr_resume, -1));
+ duk_resolve_nonbound_function(thr);
+ h_fun = duk_require_hobject(thr, -1); /* reject lightfuncs on purpose */
if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) {
goto state_error;
}
- duk_pop(ctx);
+ duk_pop(thr);
}
/*
@@ -39293,7 +40543,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
if (is_error) {
- DUK_ASSERT_TOP(ctx, 2); /* value (error) is at stack top */
+ DUK_ASSERT_TOP(thr, 2); /* value (error) is at stack top */
duk_err_augment_error_throw(thr); /* in resumer's context */
}
#endif
@@ -39301,16 +40551,16 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
#if defined(DUK_USE_DEBUG)
if (is_error) {
DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
} else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
} else {
DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
}
#endif
@@ -39353,20 +40603,19 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
*/
#if defined(DUK_USE_COROUTINE_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) {
duk_hobject *caller_func;
- duk_small_int_t is_error;
+ duk_small_uint_t is_error;
DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
+ (duk_tval *) duk_get_tval(thr, 0),
+ (duk_tval *) duk_get_tval(thr, 1)));
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->heap->curr_thread == thr);
- is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
- duk_set_top(ctx, 1);
+ is_error = (duk_small_uint_t) duk_to_boolean(thr, 1);
+ duk_set_top(thr, 1);
/* [ value ] */
@@ -39385,11 +40634,12 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
goto state_error;
}
DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr - 1) != NULL); /* caller */
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
- caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr - 1);
+ caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
goto state_error;
@@ -39412,7 +40662,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
if (is_error) {
- DUK_ASSERT_TOP(ctx, 1); /* value (error) is at stack top */
+ DUK_ASSERT_TOP(thr, 1); /* value (error) is at stack top */
duk_err_augment_error_throw(thr); /* in yielder's context */
}
#endif
@@ -39420,10 +40670,10 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
#if defined(DUK_USE_DEBUG)
if (is_error) {
DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0)));
+ (duk_tval *) duk_get_tval(thr, 0)));
} else {
DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0)));
+ (duk_tval *) duk_get_tval(thr, 0)));
}
#endif
@@ -39454,8 +40704,8 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
#endif
#if defined(DUK_USE_COROUTINE_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
- duk_push_current_thread(ctx);
+DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_hthread *thr) {
+ duk_push_current_thread(thr);
return 1;
}
#endif
@@ -39465,8 +40715,8 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
/* #include duk_internal.h -> already included */
-DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) {
- DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
+DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_hthread *thr) {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/*
* Fixed buffer helper useful for debugging, requires no allocation
@@ -39519,7 +40769,7 @@ DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
}
} else {
/* normal */
- fb->offset += res;
+ fb->offset += (duk_size_t) res;
}
}
va_end(ap);
@@ -39612,9 +40862,9 @@ DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
#define DUK__LOOP_STACK_DEPTH 256
/* must match bytecode defines now; build autogenerate? */
-DUK_LOCAL const char *duk__bc_optab[256] = {
- "LDREG", "STREG", "LDCONST", "LDINT", "LDINTX", "LDTHIS", "LDUNDEF", "LDNULL",
- "LDTRUE", "LDFALSE", "BNOT", "LNOT", "UNM", "UNP", "TYPEOF", "TYPEOFID",
+DUK_LOCAL const char * const duk__bc_optab[256] = {
+ "LDREG", "STREG", "JUMP", "LDCONST", "LDINT", "LDINTX", "LDTHIS", "LDUNDEF",
+ "LDNULL", "LDTRUE", "LDFALSE", "GETVAR", "BNOT", "LNOT", "UNM", "UNP",
"EQ_RR", "EQ_CR", "EQ_RC", "EQ_CC", "NEQ_RR", "NEQ_CR", "NEQ_RC", "NEQ_CC",
"SEQ_RR", "SEQ_CR", "SEQ_RC", "SEQ_CC", "SNEQ_RR", "SNEQ_CR", "SNEQ_RC", "SNEQ_CC",
@@ -39624,28 +40874,28 @@ DUK_LOCAL const char *duk__bc_optab[256] = {
"SUB_RR", "SUB_CR", "SUB_RC", "SUB_CC", "MUL_RR", "MUL_CR", "MUL_RC", "MUL_CC",
"DIV_RR", "DIV_CR", "DIV_RC", "DIV_CC", "MOD_RR", "MOD_CR", "MOD_RC", "MOD_CC",
- "BAND_RR", "BAND_CR", "BAND_RC", "BAND_CC", "BOR_RR", "BOR_CR", "BOR_RC", "BOR_CC",
- "BXOR_RR", "BXOR_CR", "BXOR_RC", "BXOR_CC", "BASL_RR", "BASL_CR", "BASL_RC", "BASL_CC",
- "BLSR_RR", "BLSR_CR", "BLSR_RC", "BLSR_CC", "BASR_RR", "BASR_CR", "BASR_RC", "BASR_CC",
+ "EXP_RR", "EXP_CR", "EXP_RC", "EXP_CC", "BAND_RR", "BAND_CR", "BAND_RC", "BAND_CC",
+ "BOR_RR", "BOR_CR", "BOR_RC", "BOR_CC", "BXOR_RR", "BXOR_CR", "BXOR_RC", "BXOR_CC",
+ "BASL_RR", "BASL_CR", "BASL_RC", "BASL_CC", "BLSR_RR", "BLSR_CR", "BLSR_RC", "BLSR_CC",
- "INSTOF_RR", "INSTOF_CR", "INSTOF_RC", "INSTOF_CC", "IN_RR", "IN_CR", "IN_RC", "IN_CC",
+ "BASR_RR", "BASR_CR", "BASR_RC", "BASR_CC", "INSTOF_RR", "INSTOF_CR", "INSTOF_RC", "INSTOF_CC",
+ "IN_RR", "IN_CR", "IN_RC", "IN_CC", "GETPROP_RR", "GETPROP_CR", "GETPROP_RC", "GETPROP_CC",
+ "PUTPROP_RR", "PUTPROP_CR", "PUTPROP_RC", "PUTPROP_CC", "DELPROP_RR", "DELPROP_CR", "DELPROP_RC", "DELPROP_CC",
"PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
+
"PREINCP_RR", "PREINCP_CR", "PREINCP_RC", "PREINCP_CC", "PREDECP_RR", "PREDECP_CR", "PREDECP_RC", "PREDECP_CC",
"POSTINCP_RR", "POSTINCP_CR", "POSTINCP_RC", "POSTINCP_CC", "POSTDECP_RR", "POSTDECP_CR", "POSTDECP_RC", "POSTDECP_CC",
-
- "GETPROP_RR", "GETPROP_CR", "GETPROP_RC", "GETPROP_CC", "PUTPROP_RR", "PUTPROP_CR", "PUTPROP_RC", "PUTPROP_CC",
- "DELPROP_RR", "DELPROP_CR", "DELPROP_RC", "DELPROP_CC", "DECLVAR_RR", "DECLVAR_CR", "DECLVAR_RC", "DECLVAR_CC",
- "REGEXP_RR", "REGEXP_RC", "REGEXP_CR", "REGEXP_CC", "CSVAR_RR", "CSVAR_CR", "CSVAR_RC", "CSVAR_CC",
- "CLOSURE", "GETVAR", "PUTVAR", "DELVAR", "JUMP", "RETREG", "RETUNDEF", "RETCONST",
+ "DECLVAR_RR", "DECLVAR_CR", "DECLVAR_RC", "DECLVAR_CC", "REGEXP_RR", "REGEXP_RC", "REGEXP_CR", "REGEXP_CC",
+ "CLOSURE", "TYPEOF", "TYPEOFID", "PUTVAR", "DELVAR", "RETREG", "RETUNDEF", "RETCONST",
"RETCONSTN", "LABEL", "ENDLABEL", "BREAK", "CONTINUE", "TRYCATCH", "ENDTRY", "ENDCATCH",
- "ENDFIN", "THROW", "CSREG", "EVALCALL", "CALL", "TAILCALL", "NEW", "NEWOBJ",
- "NEWARR", "MPUTOBJ", "MPUTOBJI", "INITSET", "INITGET", "MPUTARR", "MPUTARRI", "SETALEN",
- "INITENUM", "NEXTENUM", "INVLHS", "DEBUGGER", "NOP", "INVALID", "UNUSED190", "UNUSED191",
+ "ENDFIN", "THROW", "INVLHS", "CSREG", "CSVAR_RR", "CSVAR_CR", "CSVAR_RC", "CSVAR_CC",
+ "CALL0", "CALL1", "CALL2", "CALL3", "CALL4", "CALL5", "CALL6", "CALL7",
+ "CALL8", "CALL9", "CALL10", "CALL11", "CALL12", "CALL13", "CALL14", "CALL15",
- "UNUSED192", "UNUSED193", "UNUSED194", "UNUSED195", "UNUSED196", "UNUSED197", "UNUSED198", "UNUSED199",
- "UNUSED200", "UNUSED201", "UNUSED202", "UNUSED203", "UNUSED204", "UNUSED205", "UNUSED206", "UNUSED207",
- "UNUSED208", "UNUSED209", "UNUSED210", "UNUSED211", "UNUSED212", "UNUSED213", "UNUSED214", "UNUSED215",
+ "NEWOBJ", "NEWARR", "MPUTOBJ", "MPUTOBJI", "INITSET", "INITGET", "MPUTARR", "MPUTARRI",
+ "SETALEN", "INITENUM", "NEXTENUM", "NEWTARGET", "DEBUGGER", "NOP", "INVALID", "UNUSED207",
+ "GETPROPC_RR", "GETPROPC_CR", "GETPROPC_RC", "GETPROPC_CC", "UNUSED212", "UNUSED213", "UNUSED214", "UNUSED215",
"UNUSED216", "UNUSED217", "UNUSED218", "UNUSED219", "UNUSED220", "UNUSED221", "UNUSED222", "UNUSED223",
"UNUSED224", "UNUSED225", "UNUSED226", "UNUSED227", "UNUSED228", "UNUSED229", "UNUSED230", "UNUSED231",
@@ -39800,9 +41050,9 @@ DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_boo
p_end = p + DUK_HSTRING_GET_BYTELEN(h);
if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
- /* if property key begins with underscore, encode it with
+ /* If property key begins with underscore, encode it with
* forced quotes (e.g. "_Foo") to distinguish it from encoded
- * internal properties (e.g. \xffBar -> _Bar).
+ * internal properties (e.g. \x82Bar -> _Bar).
*/
quotes = 1;
}
@@ -39820,9 +41070,9 @@ DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_boo
duk_fb_sprintf(fb, "\\\"");
} else if (ch >= 0x20 && ch <= 0x7e) {
duk_fb_put_byte(fb, ch);
- } else if (ch == 0xff && !quotes) {
- /* encode \xffBar as _Bar if no quotes are applied, this is for
- * readable internal keys.
+ } else if (ch == 0x82 && !quotes) {
+ /* encode \x82Bar as _Bar if no quotes are
+ * applied, this is for readable internal keys.
*/
duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
} else {
@@ -40015,9 +41265,6 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
}
- if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_dukfunc:true");
- }
if (DUK_HOBJECT_IS_BUFOBJ(h)) {
DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true");
}
@@ -40054,7 +41301,7 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
duk_hdecenv *e = (duk_hdecenv *) h;
DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread);
DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap);
- DUK__COMMA(); duk_fb_sprintf(fb, "__regbase:%ld", (long) e->regbase);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__regbase_byteoff:%ld", (long) e->regbase_byteoff);
} else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) {
duk_hobjenv *e = (duk_hobjenv *) h;
DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target);
@@ -40071,23 +41318,35 @@ DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
#endif
+ } else if (st->internal && DUK_HOBJECT_IS_PROXY(h)) {
+ duk_hproxy *p = (duk_hproxy *) h;
+ DUK__COMMA(); duk_fb_sprintf(fb, "__target:");
+ duk__print_hobject(st, p->target);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__handler:");
+ duk__print_hobject(st, p->handler);
} else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ DUK__COMMA(); duk_fb_sprintf(fb, "__ptr_curr_pc:%p", (void *) t->ptr_curr_pc);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__heap:%p", (void *) t->heap);
DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
- DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%ld", (long) t->valstack_max);
- DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%ld", (long) t->callstack_max);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%ld", (long) t->catchstack_max);
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
+ DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_alloc_end:%p/%ld", (void *) t->valstack_alloc_end, (long) (t->valstack_alloc_end - t->valstack));
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%ld", (long) t->catchstack_size);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%ld", (long) t->catchstack_top);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_curr:%p", (void *) t->callstack_curr);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_top:%ld", (long) t->callstack_top);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_preventcount:%ld", (long) t->callstack_preventcount);
DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__compile_ctx:%p", (void *) t->compile_ctx);
+#if defined(DUK_USE_INTERRUPT_COUNTER)
+ DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_counter:%ld", (long) t->interrupt_counter);
+ DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_init:%ld", (long) t->interrupt_init);
+#endif
+
/* XXX: print built-ins array? */
}
@@ -40294,7 +41553,7 @@ DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
case DUK_TAG_FASTINT:
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- duk_fb_sprintf(fb, "%.18gF", (double) DUK_TVAL_GET_NUMBER(tv));
+ duk_fb_sprintf(fb, "%.18g_F", (double) DUK_TVAL_GET_NUMBER(tv));
break;
#endif
default: {
@@ -40321,8 +41580,8 @@ DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
/* XXX: option to fix opcode length so it lines up nicely */
if (op == DUK_OP_JUMP) {
- duk_int_t diff1 = DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS; /* from next pc */
- duk_int_t diff2 = diff1 + 1; /* from curr pc */
+ duk_int_t diff1 = (duk_int_t) (DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS); /* from next pc */
+ duk_int_t diff2 = diff1 + 1; /* from curr pc */
duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
(const char *) op_name, (long) diff1,
@@ -40564,7 +41823,7 @@ DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_u
#else
ch = fptr[fptr_size - 1 - i];
#endif
- p += DUK_SNPRINTF((char *) p, left, "%02lx", (unsigned long) ch);
+ p += DUK_SNPRINTF((char *) p, (duk_size_t) left, "%02lx", (unsigned long) ch);
}
}
@@ -40585,6 +41844,24 @@ DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_u
#if defined(DUK_USE_DEBUGGER_SUPPORT)
/*
+ * Assert helpers
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+#define DUK__DBG_TPORT_ENTER() do { \
+ DUK_ASSERT(heap->dbg_calling_transport == 0); \
+ heap->dbg_calling_transport = 1; \
+ } while (0)
+#define DUK__DBG_TPORT_EXIT() do { \
+ DUK_ASSERT(heap->dbg_calling_transport == 1); \
+ heap->dbg_calling_transport = 0; \
+ } while (0)
+#else
+#define DUK__DBG_TPORT_ENTER() do {} while (0)
+#define DUK__DBG_TPORT_EXIT() do {} while (0)
+#endif
+
+/*
* Helper structs
*/
@@ -40646,10 +41923,9 @@ DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
/* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
heap->dbg_state_dirty = 0;
heap->dbg_force_restart = 0;
- heap->dbg_step_type = 0;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
+ heap->dbg_pause_flags = 0;
+ heap->dbg_pause_act = NULL;
+ heap->dbg_pause_startline = 0;
heap->dbg_have_next_byte = 0;
duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */
heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */
@@ -40668,14 +41944,12 @@ DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
duk_debug_detached_function detached_cb;
void *detached_udata;
duk_hthread *thr;
- duk_context *ctx;
thr = heap->heap_thread;
if (thr == NULL) {
DUK_ASSERT(heap->dbg_detached_cb == NULL);
return;
}
- ctx = (duk_context *) thr;
/* Safe to call multiple times. */
@@ -40690,7 +41964,7 @@ DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
* inside the callback.
*/
DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
- detached_cb(ctx, detached_udata);
+ detached_cb(thr, detached_udata);
}
heap->dbg_detaching = 0;
@@ -40723,11 +41997,40 @@ DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
}
/*
+ * Pause handling
+ */
+
+DUK_LOCAL void duk__debug_set_pause_state(duk_hthread *thr, duk_heap *heap, duk_small_uint_t pause_flags) {
+ duk_uint_fast32_t line;
+
+ line = duk_debug_curr_line(thr);
+ if (line == 0) {
+ /* No line info for current function. */
+ duk_small_uint_t updated_flags;
+
+ updated_flags = pause_flags & ~(DUK_PAUSE_FLAG_LINE_CHANGE);
+ DUK_D(DUK_DPRINT("no line info for current activation, disable line-based pause flags: 0x%08lx -> 0x%08lx",
+ (long) pause_flags, (long) updated_flags));
+ pause_flags = updated_flags;
+ }
+
+ heap->dbg_pause_flags = pause_flags;
+ heap->dbg_pause_act = thr->callstack_curr;
+ heap->dbg_pause_startline = (duk_uint32_t) line;
+ heap->dbg_state_dirty = 1;
+
+ DUK_D(DUK_DPRINT("set state for automatic pause triggers, flags=0x%08lx, act=%p, startline=%ld",
+ (long) heap->dbg_pause_flags, (void *) heap->dbg_pause_act,
+ (long) heap->dbg_pause_startline));
+}
+
+/*
* Debug connection peek and flush primitives
*/
DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
duk_heap *heap;
+ duk_bool_t ret;
DUK_ASSERT(thr != NULL);
heap = thr->heap;
@@ -40742,7 +42045,10 @@ DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
return 0;
}
- return (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
+ DUK__DBG_TPORT_ENTER();
+ ret = (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
+ DUK__DBG_TPORT_EXIT();
+ return ret;
}
DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
@@ -40761,7 +42067,9 @@ DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
return;
}
+ DUK__DBG_TPORT_ENTER();
heap->dbg_read_flush_cb(heap->dbg_udata);
+ DUK__DBG_TPORT_EXIT();
}
DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
@@ -40780,7 +42088,9 @@ DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
return;
}
+ DUK__DBG_TPORT_ENTER();
heap->dbg_write_flush_cb(heap->dbg_udata);
+ DUK__DBG_TPORT_EXIT();
}
/*
@@ -40858,7 +42168,10 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
left = 1;
#endif
+ DUK__DBG_TPORT_ENTER();
got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
+ DUK__DBG_TPORT_EXIT();
+
if (got == 0 || got > left) {
DUK_D(DUK_DPRINT("connection error during read, return zero data"));
duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
@@ -40893,7 +42206,7 @@ DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
(duk_uint32_t) buf[3];
}
-DUK_LOCAL duk_uint32_t duk__debug_read_int32_raw(duk_hthread *thr) {
+DUK_LOCAL duk_int32_t duk__debug_read_int32_raw(duk_hthread *thr) {
return (duk_int32_t) duk__debug_read_uint32_raw(thr);
}
@@ -40929,25 +42242,23 @@ DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
}
DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t buf[31];
duk_uint8_t *p;
if (len <= sizeof(buf)) {
duk_debug_read_bytes(thr, buf, (duk_size_t) len);
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) len);
} else {
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); /* zero for paranoia */
+ p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */
DUK_ASSERT(p != NULL);
duk_debug_read_bytes(thr, p, (duk_size_t) len);
- (void) duk_buffer_to_string(ctx, -1); /* Safety relies on debug client, which is OK. */
+ (void) duk_buffer_to_string(thr, -1); /* Safety relies on debug client, which is OK. */
}
- return duk_require_hstring(ctx, -1);
+ return duk_require_hstring(thr, -1);
}
DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_t x;
duk_uint32_t len;
@@ -40970,19 +42281,18 @@ 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, 1);
- duk_push_hstring_empty(ctx); /* always push some string */
- return duk_require_hstring(ctx, -1);
+ duk_push_hstring_empty(thr); /* always push some string */
+ return duk_require_hstring(thr, -1);
}
DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t *p;
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); /* zero for paranoia */
+ p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */
DUK_ASSERT(p != NULL);
duk_debug_read_bytes(thr, p, (duk_size_t) len);
- return duk_require_hbuffer(ctx, -1);
+ return duk_require_hbuffer(thr, -1);
}
DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
@@ -41066,7 +42376,6 @@ DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
}
DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t x;
duk_uint_t t;
duk_uint32_t len;
@@ -41078,11 +42387,11 @@ DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
if (x >= 0xc0) {
t = (duk_uint_t) (x - 0xc0);
t = (t << 8) + duk_debug_read_byte(thr);
- duk_push_uint(ctx, (duk_uint_t) t);
+ duk_push_uint(thr, (duk_uint_t) t);
goto return_ptr;
}
if (x >= 0x80) {
- duk_push_uint(ctx, (duk_uint_t) (x - 0x80));
+ duk_push_uint(thr, (duk_uint_t) (x - 0x80));
goto return_ptr;
}
if (x >= 0x60) {
@@ -41094,7 +42403,7 @@ DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
switch (x) {
case DUK_DBG_IB_INT4: {
duk_int32_t i = duk__debug_read_int32_raw(thr);
- duk_push_i32(ctx, i);
+ duk_push_i32(thr, i);
break;
}
case DUK_DBG_IB_STR4: {
@@ -41118,25 +42427,25 @@ DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
break;
}
case DUK_DBG_IB_UNDEFINED: {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
break;
}
case DUK_DBG_IB_NULL: {
- duk_push_null(ctx);
+ duk_push_null(thr);
break;
}
case DUK_DBG_IB_TRUE: {
- duk_push_true(ctx);
+ duk_push_true(thr);
break;
}
case DUK_DBG_IB_FALSE: {
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
}
case DUK_DBG_IB_NUMBER: {
duk_double_t d;
d = duk__debug_read_double_raw(thr);
- duk_push_number(ctx, d);
+ duk_push_number(thr, d);
break;
}
case DUK_DBG_IB_OBJECT: {
@@ -41219,7 +42528,10 @@ DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *dat
#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
left = 1;
#endif
+ DUK__DBG_TPORT_ENTER();
got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
+ DUK__DBG_TPORT_EXIT();
+
if (got == 0 || got > left) {
duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
DUK_D(DUK_DPRINT("connection error during write"));
@@ -41345,8 +42657,7 @@ DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
}
DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_debug_write_hstring(thr, duk_safe_to_hstring(ctx, -1));
+ duk_debug_write_hstring(thr, duk_safe_to_hstring(thr, -1));
}
DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
@@ -41534,7 +42845,7 @@ DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t e
DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
- duk_debug_write_int(thr, command);
+ duk_debug_write_int(thr, (duk_int32_t) command);
}
DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
@@ -41553,7 +42864,6 @@ DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
*/
DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_uint_fast32_t line;
duk_uint_fast32_t pc;
@@ -41575,20 +42885,18 @@ DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
/* XXX: this should be optimized to be a raw query and avoid valstack
* operations if possible.
*/
- duk_push_tval(ctx, &act->tv_func);
- line = duk_hobject_pc2line_query(ctx, -1, pc);
- duk_pop(ctx);
+ duk_push_tval(thr, &act->tv_func);
+ line = duk_hobject_pc2line_query(thr, -1, pc);
+ duk_pop(thr);
return line;
}
DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0));
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
act = thr->callstack_curr;
if (act == NULL) {
duk_debug_write_undefined(thr);
@@ -41596,15 +42904,14 @@ DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
duk_debug_write_int(thr, 0);
duk_debug_write_int(thr, 0);
} else {
- duk_push_tval(ctx, &act->tv_func);
- duk_get_prop_string(ctx, -1, "fileName");
+ duk_push_tval(thr, &act->tv_func);
+ duk_get_prop_string(thr, -1, "fileName");
duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_string(ctx, -2, "name");
+ duk_get_prop_string(thr, -2, "name");
duk__debug_write_hstring_safe_top(thr);
- duk_pop_3(ctx);
+ duk_pop_3(thr);
/* Report next pc/line to be executed. */
duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
- act = thr->callstack_curr;
duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
}
@@ -41617,27 +42924,26 @@ DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
* NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
*/
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_uint32_t pc;
DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */
duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
- duk_debug_write_int(thr, fatal);
+ duk_debug_write_int(thr, (duk_int32_t) fatal);
/* Report thrown value to client coerced to string */
- duk_dup_top(ctx);
+ duk_dup_top(thr);
duk__debug_write_hstring_safe_top(thr);
- duk_pop(ctx);
+ duk_pop(thr);
- if (duk_is_error(ctx, -1)) {
+ if (duk_is_error(thr, -1)) {
/* Error instance, use augmented error data directly */
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_FILE_NAME);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER);
- duk_debug_write_uint(thr, duk_get_uint(ctx, -1));
- duk_pop_2(ctx);
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER);
+ duk_debug_write_uint(thr, duk_get_uint(thr, -1));
+ duk_pop_2(thr);
} else {
/* For anything other than an Error instance, we calculate the
* error location directly from the current activation if one
@@ -41645,13 +42951,12 @@ DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
*/
act = thr->callstack_curr;
if (act != NULL) {
- duk_push_tval(ctx, &act->tv_func);
- duk_get_prop_string(ctx, -1, "fileName");
+ duk_push_tval(thr, &act->tv_func);
+ duk_get_prop_string(thr, -1, "fileName");
duk__debug_write_hstring_safe_top(thr);
- act = thr->callstack_curr;
- pc = duk_hthread_get_act_prev_pc(thr, act);
- duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc));
- duk_pop_2(ctx);
+ pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act);
+ duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc));
+ duk_pop_2(thr);
} else {
/* Can happen if duk_throw() is called on an empty
* callstack.
@@ -41684,7 +42989,7 @@ DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
return 0;
}
if (x >= 0x60) {
- duk_debug_skip_bytes(thr, x - 0x60);
+ duk_debug_skip_bytes(thr, (duk_size_t) (x - 0x60));
return 0;
}
switch(x) {
@@ -41752,6 +43057,9 @@ DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
}
}
+/* Read and validate a call stack index. If index is invalid, write out an
+ * error message and return zero.
+ */
DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) {
duk_int32_t level;
level = duk_debug_read_int(thr);
@@ -41762,6 +43070,21 @@ DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) {
return level;
}
+/* Read a call stack index and lookup the corresponding duk_activation.
+ * If index is invalid, write out an error message and return NULL.
+ */
+DUK_LOCAL duk_activation *duk__debug_read_level_get_activation(duk_hthread *thr) {
+ duk_activation *act;
+ duk_int32_t level;
+
+ level = duk_debug_read_int(thr);
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act == NULL) {
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
+ }
+ return act;
+}
+
/*
* Simple commands
*/
@@ -41798,50 +43121,61 @@ DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap
DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
DUK_D(DUK_DPRINT("debug command Pause"));
-
- if (duk_debug_is_paused(heap)) {
- DUK_D(DUK_DPRINT("Pause requested when already paused, ignore"));
- } else {
- duk_debug_set_paused(heap);
- }
+ duk_debug_set_paused(heap);
duk_debug_write_reply(thr);
duk_debug_write_eom(thr);
}
DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
+ duk_small_uint_t pause_flags;
+
DUK_D(DUK_DPRINT("debug command Resume"));
duk_debug_clear_paused(heap);
+
+ pause_flags = 0;
+#if 0 /* manual testing */
+ pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE;
+ pause_flags |= DUK_PAUSE_FLAG_CAUGHT_ERROR;
+ pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
+#endif
+#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
+ pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
+#endif
+
+ duk__debug_set_pause_state(thr, heap, pause_flags);
+
duk_debug_write_reply(thr);
duk_debug_write_eom(thr);
}
DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
- duk_small_uint_t step_type;
- duk_uint_fast32_t line;
+ duk_small_uint_t pause_flags;
DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
if (cmd == DUK_DBG_CMD_STEPINTO) {
- step_type = DUK_STEP_TYPE_INTO;
+ pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
+ DUK_PAUSE_FLAG_FUNC_ENTRY |
+ DUK_PAUSE_FLAG_FUNC_EXIT;
} else if (cmd == DUK_DBG_CMD_STEPOVER) {
- step_type = DUK_STEP_TYPE_OVER;
+ pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
+ DUK_PAUSE_FLAG_FUNC_EXIT;
} else {
DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
- step_type = DUK_STEP_TYPE_OUT;
+ pause_flags = DUK_PAUSE_FLAG_FUNC_EXIT;
}
+#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
+ pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
+#endif
+
+ /* If current activation doesn't have line information, line-based
+ * pause flags are automatically disabled. As a result, e.g.
+ * StepInto will then pause on (native) function entry or exit.
+ */
+ duk_debug_clear_paused(heap);
+ duk__debug_set_pause_state(thr, heap, pause_flags);
- line = duk_debug_curr_line(thr);
- if (line > 0) {
- duk_debug_clear_paused(heap); /* XXX: overlap with fields below; separate macro/helper? */
- heap->dbg_step_type = step_type;
- heap->dbg_step_thread = thr;
- heap->dbg_step_csindex = thr->callstack_top - 1;
- heap->dbg_step_startline = line;
- heap->dbg_state_dirty = 1;
- } else {
- DUK_D(DUK_DPRINT("cannot determine current line, stepinto/stepover/stepout ignored"));
- }
duk_debug_write_reply(thr);
duk_debug_write_eom(thr);
}
@@ -41894,40 +43228,27 @@ DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
+ duk_activation *act;
duk_hstring *str;
duk_bool_t rc;
- duk_int32_t level;
DUK_UNREF(heap);
DUK_D(DUK_DPRINT("debug command GetVar"));
- level = duk__debug_read_validate_csindex(thr);
- if (level == 0) {
+ act = duk__debug_read_level_get_activation(thr);
+ if (act == NULL) {
return;
}
str = duk_debug_read_hstring(thr); /* push to stack */
DUK_ASSERT(str != NULL);
- if (thr->callstack_top > 0) {
- rc = duk_js_getvar_activation(thr,
- thr->callstack + thr->callstack_top + level,
- str,
- 0);
- } else {
- /* No activation, no variable access. Could also pretend
- * we're in the global program context and read stuff off
- * the global object.
- */
- DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
- rc = 0;
- }
+ rc = duk_js_getvar_activation(thr, act, str, 0);
duk_debug_write_reply(thr);
if (rc) {
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_ASSERT(duk_get_tval(thr, -2) != NULL);
+ duk_debug_write_tval(thr, duk_get_tval(thr, -2));
} else {
duk_debug_write_int(thr, 0);
duk_debug_write_unused(thr);
@@ -41936,15 +43257,15 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
+ duk_activation *act;
duk_hstring *str;
duk_tval *tv;
- duk_int32_t level;
DUK_UNREF(heap);
DUK_D(DUK_DPRINT("debug command PutVar"));
- level = duk__debug_read_validate_csindex(thr);
- if (level == 0) {
+ act = duk__debug_read_level_get_activation(thr);
+ if (act == NULL) {
return;
}
str = duk_debug_read_hstring(thr); /* push to stack */
@@ -41955,15 +43276,7 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
return;
}
- if (thr->callstack_top > 0) {
- duk_js_putvar_activation(thr,
- thr->callstack + thr->callstack_top + level,
- str,
- tv,
- 0);
- } else {
- DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
- }
+ duk_js_putvar_activation(thr, act, str, tv, 0);
/* XXX: Current putvar implementation doesn't have a success flag,
* add one and send to debug client?
@@ -41973,23 +43286,17 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
duk_hthread *curr_thr = thr;
duk_activation *curr_act;
duk_uint_fast32_t pc;
duk_uint_fast32_t line;
- duk_size_t i;
DUK_ASSERT(thr != NULL);
DUK_UNREF(heap);
duk_debug_write_reply(thr);
while (curr_thr != NULL) {
- i = curr_thr->callstack_top;
- while (i > 0) {
- i--;
- curr_act = curr_thr->callstack + i;
-
+ for (curr_act = curr_thr->callstack_curr; curr_act != NULL; curr_act = curr_act->parent) {
/* PC/line semantics here are:
* - For callstack top we're conceptually between two
* opcodes and current PC indicates next line to
@@ -42003,19 +43310,19 @@ DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap
/* XXX: optimize to use direct reads, i.e. avoid
* value stack operations.
*/
- duk_push_tval(ctx, &curr_act->tv_func);
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_FILE_NAME);
+ duk_push_tval(thr, &curr_act->tv_func);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME);
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
duk__debug_write_hstring_safe_top(thr);
pc = duk_hthread_get_act_curr_pc(thr, curr_act);
- if (i != curr_thr->callstack_top - 1 && pc > 0) {
+ if (curr_act != curr_thr->callstack_curr && pc > 0) {
pc--;
}
- line = duk_hobject_pc2line_query(ctx, -3, pc);
+ line = duk_hobject_pc2line_query(thr, -3, pc);
duk_debug_write_uint(thr, (duk_uint32_t) line);
duk_debug_write_uint(thr, (duk_uint32_t) pc);
- duk_pop_3(ctx);
+ duk_pop_3(thr);
}
curr_thr = curr_thr->resumer;
}
@@ -42026,20 +43333,17 @@ 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_activation *act;
duk_hstring *varname;
DUK_UNREF(heap);
- level = duk__debug_read_validate_csindex(thr);
- if (level == 0) {
+ act = duk__debug_read_level_get_activation(thr);
+ if (act == NULL) {
return;
}
- duk_debug_write_reply(thr);
- curr_act = thr->callstack + thr->callstack_top + level;
+ duk_debug_write_reply(thr);
/* XXX: several nice-to-have improvements here:
* - Use direct reads avoiding value stack operations
@@ -42047,18 +43351,18 @@ DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
* - If side effects are possible, add error catching
*/
- duk_push_tval(ctx, &curr_act->tv_func);
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VARMAP);
- if (duk_is_object(ctx, -1)) {
- duk_enum(ctx, -1, 0 /*enum_flags*/);
- while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
- varname = duk_known_hstring(ctx, -1);
+ duk_push_tval(thr, &act->tv_func);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VARMAP);
+ if (duk_is_object(thr, -1)) {
+ duk_enum(thr, -1, 0 /*enum_flags*/);
+ while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
+ varname = duk_known_hstring(thr, -1);
- duk_js_getvar_activation(thr, curr_act, varname, 0 /*throw_flag*/);
+ duk_js_getvar_activation(thr, act, varname, 0 /*throw_flag*/);
/* [ ... func varmap enum key value this ] */
- duk_debug_write_hstring(thr, duk_get_hstring(ctx, -3));
- duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
- duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
+ duk_debug_write_hstring(thr, duk_get_hstring(thr, -3));
+ duk_debug_write_tval(thr, duk_get_tval(thr, -2));
+ duk_pop_3(thr); /* -> [ ... func varmap enum ] */
}
} else {
DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
@@ -42068,13 +43372,12 @@ 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;
- duk_int_t num_eval_args;
duk_bool_t direct_eval;
duk_int32_t level;
+ duk_idx_t idx_func;
DUK_UNREF(heap);
@@ -42089,8 +43392,9 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
*/
/* nargs == 2 so we can pass a callstack index to eval(). */
- duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/);
- duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
+ idx_func = duk_get_top(thr);
+ duk_push_c_function(thr, duk_bi_global_object_eval, 2 /*nargs*/);
+ duk_push_undefined(thr); /* 'this' binding shouldn't matter here */
/* Read callstack index, if non-null. */
if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) {
@@ -42110,32 +43414,31 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
(void) duk_debug_read_hstring(thr);
if (direct_eval) {
- num_eval_args = 2;
- duk_push_int(ctx, level - 1); /* compensate for eval() call */
- } else {
- num_eval_args = 1;
+ duk_push_int(thr, level - 1); /* compensate for eval() call */
}
- /* [ ... eval "eval" eval_input level ] */
+ /* [ ... eval "eval" eval_input level? ] */
call_flags = 0;
- if (direct_eval && thr->callstack_top >= (duk_size_t) -level) {
+ if (direct_eval) {
duk_activation *act;
duk_hobject *fun;
- act = thr->callstack + thr->callstack_top + level;
- fun = DUK_ACT_GET_FUNC(act);
- if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(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 do an indirect eval instead.
- */
- call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act != NULL) {
+ fun = DUK_ACT_GET_FUNC(act);
+ if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(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 do an indirect eval instead.
+ */
+ call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
+ }
}
}
- call_ret = duk_handle_call_protected(thr, num_eval_args, call_flags);
+ call_ret = duk_pcall_method_flags(thr, duk_get_top(thr) - (idx_func + 2), call_flags);
if (call_ret == DUK_EXEC_SUCCESS) {
eval_err = 0;
@@ -42146,15 +43449,15 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
* to traverse the error object.
*/
eval_err = 1;
- duk_safe_to_string(ctx, -1);
+ duk_safe_to_string(thr, -1);
}
/* [ ... result ] */
duk_debug_write_reply(thr);
duk_debug_write_int(thr, (duk_int32_t) eval_err);
- DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
- duk_debug_write_tval(thr, duk_get_tval(ctx, -1));
+ DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
+ duk_debug_write_tval(thr, duk_get_tval(thr, -1));
duk_debug_write_eom(thr);
}
@@ -42170,12 +43473,11 @@ DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
}
DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
duk_idx_t old_top;
DUK_D(DUK_DPRINT("debug command AppRequest"));
- old_top = duk_get_top(ctx); /* save stack top */
+ old_top = duk_get_top(thr); /* save stack top */
if (heap->dbg_request_cb != NULL) {
duk_idx_t nrets;
@@ -42187,7 +43489,7 @@ DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
*/
while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
duk_tval *tv;
- if (!duk_check_stack(ctx, 1)) {
+ if (!duk_check_stack(thr, 1)) {
DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
goto fail;
}
@@ -42198,41 +43500,41 @@ DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
}
nvalues++;
}
- DUK_ASSERT(duk_get_top(ctx) == old_top + nvalues);
+ DUK_ASSERT(duk_get_top(thr) == old_top + nvalues);
/* Request callback should push values for reply to client onto valstack */
DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
- (long) nvalues, (long) old_top, (long) duk_get_top(ctx)));
- nrets = heap->dbg_request_cb(ctx, heap->dbg_udata, nvalues);
+ (long) nvalues, (long) old_top, (long) duk_get_top(thr)));
+ nrets = heap->dbg_request_cb(thr, heap->dbg_udata, nvalues);
DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
- (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(ctx)));
+ (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(thr)));
if (nrets >= 0) {
- DUK_ASSERT(duk_get_top(ctx) >= old_top + nrets);
- if (duk_get_top(ctx) < old_top + nrets) {
+ DUK_ASSERT(duk_get_top(thr) >= old_top + nrets);
+ if (duk_get_top(thr) < old_top + nrets) {
DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
"top=%ld < old_top=%ld + nrets=%ld; "
"this might mean it's unsafe to continue!",
- (long) duk_get_top(ctx), (long) old_top, (long) nrets));
+ (long) duk_get_top(thr), (long) old_top, (long) nrets));
goto fail;
}
/* Reply with tvals pushed by request callback */
duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
- top = duk_get_top(ctx);
+ top = duk_get_top(thr);
for (idx = top - nrets; idx < top; idx++) {
- duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(ctx, idx));
+ duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(thr, idx));
}
duk_debug_write_eom(thr);
} else {
- DUK_ASSERT(duk_get_top(ctx) >= old_top + 1);
- if (duk_get_top(ctx) < old_top + 1) {
+ DUK_ASSERT(duk_get_top(thr) >= old_top + 1);
+ if (duk_get_top(thr) < old_top + 1) {
DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
goto fail;
}
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(ctx, -1));
+ duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(thr, -1));
}
- duk_set_top(ctx, old_top); /* restore stack top */
+ duk_set_top(thr, old_top); /* restore stack top */
} else {
DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
@@ -42241,7 +43543,7 @@ DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
return;
fail:
- duk_set_top(ctx, old_top); /* restore stack top */
+ duk_set_top(thr, old_top); /* restore stack top */
DUK__SET_CONN_BROKEN(thr, 1);
}
@@ -42269,9 +43571,9 @@ DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_hea
case DUK_HTYPE_STRING: {
duk_hstring *h = (duk_hstring *) hdr;
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_BYTELEN(h));
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_CHARLEN(h));
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_HASH(h));
+ duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_BYTELEN(h));
+ duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_CHARLEN(h));
+ duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
duk_debug_write_hstring(thr, h);
break;
}
@@ -42398,11 +43700,10 @@ DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap)
}
if (fun == NULL) {
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack index for GetBytecode"));
+ act = duk_hthread_get_activation_for_level(thr, level);
+ if (act == NULL) {
goto fail_index;
}
- act = thr->callstack + thr->callstack_top + level;
fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
}
@@ -42494,6 +43795,7 @@ DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
"extensible",
"constructable",
+ "callable",
"boundfunc",
"compfunc",
"natfunc",
@@ -42505,17 +43807,18 @@ DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
"newenv",
"namebinding",
"createargs",
- "have_finalizer"
+ "have_finalizer",
"exotic_array",
"exotic_stringobj",
"exotic_arguments",
- "exotic_dukfunc",
- "exotic_proxyobj"
+ "exotic_proxyobj",
+ "special_call"
/* NULL not needed here */
};
DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
DUK_HOBJECT_FLAG_EXTENSIBLE,
DUK_HOBJECT_FLAG_CONSTRUCTABLE,
+ DUK_HOBJECT_FLAG_CALLABLE,
DUK_HOBJECT_FLAG_BOUNDFUNC,
DUK_HOBJECT_FLAG_COMPFUNC,
DUK_HOBJECT_FLAG_NATFUNC,
@@ -42531,8 +43834,8 @@ DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC,
DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
+ DUK_HOBJECT_FLAG_SPECIAL_CALL,
0 /* terminator */
};
DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
@@ -42575,7 +43878,7 @@ DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const *
for (;;) {
mask = *masks++;
- if (!mask) {
+ if (mask == 0) {
break;
}
key = *keys++;
@@ -42657,6 +43960,10 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
DUK_UNREF(heap);
+ DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1);
+ DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1);
+ DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1);
+
h = duk_debug_read_any_ptr(thr);
if (!h) {
duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
@@ -42734,7 +44041,7 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
duk_harray *h_arr;
h_arr = (duk_harray *) h_obj;
- duk__debug_getinfo_prop_int(thr, "length", h_arr->length);
+ duk__debug_getinfo_prop_uint(thr, "length", (duk_uint_t) h_arr->length);
duk__debug_getinfo_prop_bool(thr, "length_nonwritable", h_arr->length_nonwritable);
}
@@ -42786,6 +44093,19 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
}
}
+ if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) {
+ duk_hboundfunc *h_bfun;
+ h_bfun = (duk_hboundfunc *) h_obj;
+
+ duk__debug_getinfo_flags_key(thr, "target");
+ duk_debug_write_tval(thr, &h_bfun->target);
+ duk__debug_getinfo_flags_key(thr, "this_binding");
+ duk_debug_write_tval(thr, &h_bfun->this_binding);
+ duk__debug_getinfo_flags_key(thr, "nargs");
+ duk_debug_write_int(thr, h_bfun->nargs);
+ /* h_bfun->args not exposed now */
+ }
+
if (DUK_HOBJECT_IS_THREAD(h_obj)) {
/* XXX: Currently no inspection of threads, e.g. value stack, call
* stack, catch stack, etc.
@@ -42803,7 +44123,7 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread));
duk__debug_getinfo_flags_key(thr, "varmap");
duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap));
- duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase);
+ duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase_byteoff);
}
if (DUK_HOBJECT_IS_OBJENV(h_obj)) {
@@ -42909,8 +44229,8 @@ DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_h
DUK_UNREF(heap);
h = duk_debug_read_any_ptr(thr);
- idx_start = duk_debug_read_int(thr);
- idx_end = duk_debug_read_int(thr);
+ idx_start = (duk_uint_t) duk_debug_read_int(thr);
+ idx_end = (duk_uint_t) duk_debug_read_int(thr);
if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
goto fail_args;
}
@@ -42951,7 +44271,6 @@ DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_h
* 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;
@@ -42960,9 +44279,8 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
- DUK_UNREF(ctx);
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
x = duk_debug_read_byte(thr);
switch (x) {
@@ -43084,14 +44402,14 @@ 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_ASSERT(duk_get_top(thr) >= entry_top);
+ duk_set_top(thr, entry_top);
duk__debug_skip_to_eom(thr);
return;
fail:
- DUK_ASSERT(duk_get_top(ctx) >= entry_top);
- duk_set_top(ctx, entry_top);
+ DUK_ASSERT(duk_get_top(thr) >= entry_top);
+ duk_set_top(thr, entry_top);
DUK__SET_CONN_BROKEN(thr, 1);
return;
}
@@ -43104,23 +44422,21 @@ DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
}
DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
- duk_context *ctx = (duk_context *) thr;
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t entry_top;
#endif
duk_bool_t retval = 0;
DUK_ASSERT(thr != NULL);
- DUK_UNREF(ctx);
DUK_ASSERT(thr->heap != NULL);
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#endif
DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
(long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
- DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(ctx)));
+ DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(thr)));
/* thr->heap->dbg_detaching may be != 0 if a debugger write outside
* the message loop caused a transport error and detach1() to run.
@@ -43139,7 +44455,7 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t
/* Process messages until we're no longer paused or we peek
* and see there's nothing to read right now.
*/
- DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(ctx)));
+ DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(thr)));
DUK_ASSERT(thr->heap->dbg_processing == 1);
while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
@@ -43210,11 +44526,11 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t
duk_debug_read_flush(thr); /* this cannot initiate a detach */
DUK_ASSERT(thr->heap->dbg_detaching == 0);
- DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(ctx)));
+ DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(thr)));
#if defined(DUK_USE_ASSERTIONS)
/* Easy to get wrong, so assert for it. */
- DUK_ASSERT(entry_top == duk_get_top(ctx));
+ DUK_ASSERT(entry_top == duk_get_top(thr));
#endif
return retval;
@@ -43322,7 +44638,7 @@ DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstr
b->line = line;
DUK_HSTRING_INCREF(thr, filename);
- return heap->dbg_breakpoint_count - 1; /* index */
+ return (duk_small_int_t) (heap->dbg_breakpoint_count - 1); /* index */
}
DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
@@ -43386,7 +44702,7 @@ DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) {
} else {
DUK_HEAP_SET_DEBUGGER_PAUSED(heap);
heap->dbg_state_dirty = 1;
- duk_debug_clear_step_state(heap);
+ duk_debug_clear_pause_state(heap);
DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */
heap->ms_running = 1; /* prevent mark-and-sweep, prevent refzero queueing */
heap->ms_prevent_count++;
@@ -43399,7 +44715,7 @@ DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) {
if (duk_debug_is_paused(heap)) {
DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap);
heap->dbg_state_dirty = 1;
- duk_debug_clear_step_state(heap);
+ duk_debug_clear_pause_state(heap);
DUK_ASSERT(heap->ms_running == 1);
DUK_ASSERT(heap->ms_prevent_count > 0);
heap->ms_prevent_count--;
@@ -43410,11 +44726,10 @@ DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) {
}
}
-DUK_INTERNAL void duk_debug_clear_step_state(duk_heap *heap) {
- heap->dbg_step_type = DUK_STEP_TYPE_NONE;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
+DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) {
+ heap->dbg_pause_flags = 0;
+ heap->dbg_pause_act = NULL;
+ heap->dbg_pause_startline = 0;
}
#else /* DUK_USE_DEBUGGER_SUPPORT */
@@ -43424,6 +44739,8 @@ DUK_INTERNAL void duk_debug_clear_step_state(duk_heap *heap) {
#endif /* DUK_USE_DEBUGGER_SUPPORT */
/* automatic undefs */
+#undef DUK__DBG_TPORT_ENTER
+#undef DUK__DBG_TPORT_EXIT
#undef DUK__SET_CONN_BROKEN
/*
* Augmenting errors at their creation site and their throw site.
@@ -43487,17 +44804,15 @@ DUK_INTERNAL void duk_debug_clear_step_state(duk_heap *heap) {
#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv_hnd;
- duk_small_uint_t call_flags;
duk_int_t rc;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT_STRIDX_VALID(stridx_cb);
- if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
- DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore"));
+ if (thr->heap->augmenting_error) {
+ DUK_D(DUK_DPRINT("recursive call to error augmentation, ignore"));
return;
}
@@ -43532,45 +44847,33 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
}
DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
(duk_tval *) tv_hnd));
- duk_push_tval(ctx, tv_hnd);
+ duk_push_tval(thr, tv_hnd);
/* [ ... errval errhandler ] */
- duk_insert(ctx, -2); /* -> [ ... errhandler errval ] */
- duk_push_undefined(ctx);
- duk_insert(ctx, -2); /* -> [ ... errhandler undefined(= this) errval ] */
+ duk_insert(thr, -2); /* -> [ ... errhandler errval ] */
+ duk_push_undefined(thr);
+ duk_insert(thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */
/* [ ... errhandler undefined errval ] */
/*
- * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
- * recursion depth limit (and won't increase it either). This is
- * dangerous, but useful because it allows the error handler to run
- * even if the original error is caused by C recursion depth limit.
- *
- * The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
- * duration of the error handler and cleared afterwards. This flag
- * prevents the error handler from running recursively. The flag is
- * heap level so that the flag properly controls even coroutines
- * launched by an error handler. Since the flag is heap level, it is
- * critical to restore it correctly.
+ * heap->augmenting_error prevents recursive re-entry and also causes
+ * call handling to use a larger (but not unbounded) call stack limit
+ * for the duration of error augmentation.
*
* We ignore errors now: a success return and an error value both
* replace the original error value. (This would be easy to change.)
*/
- DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */
- DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
-
- call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
+ DUK_ASSERT(thr->heap->augmenting_error == 0);
+ thr->heap->augmenting_error = 1;
- rc = duk_handle_call_protected(thr,
- 1, /* num args */
- call_flags); /* call_flags */
+ rc = duk_pcall_method(thr, 1);
DUK_UNREF(rc); /* no need to check now: both success and error are OK */
- DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
- DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);
+ DUK_ASSERT(thr->heap->augmenting_error == 1);
+ thr->heap->augmenting_error = 0;
/* [ ... errval ] */
}
@@ -43581,12 +44884,10 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
*/
#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;
- duk_int_t i, i_min;
+DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
+ duk_activation *act;
+ duk_int_t depth;
duk_int_t arr_size;
- duk_harray *a;
duk_tval *tv;
duk_hstring *s;
duk_uint32_t u32;
@@ -43594,7 +44895,6 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr_callstack != NULL);
- DUK_ASSERT(ctx != NULL);
/* [ ... error ] */
@@ -43607,13 +44907,25 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
*/
DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* Preallocate array to correct size, so that we can just write out
* the _Tracedata values into the array part.
*/
+ act = thr->callstack_curr;
depth = DUK_USE_TRACEBACK_DEPTH;
- arr_size = (duk_int_t) (thr_callstack->callstack_top <= depth ? thr_callstack->callstack_top : depth) * 2;
+ DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
+ if (depth > (duk_int_t) thr_callstack->callstack_top) {
+ depth = (duk_int_t) thr_callstack->callstack_top;
+ }
+ if (depth > 0) {
+ if (flags & DUK_AUGMENT_FLAG_SKIP_ONE) {
+ DUK_ASSERT(act != NULL);
+ act = act->parent;
+ depth--;
+ }
+ }
+ arr_size = depth * 2;
if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
arr_size += 2;
}
@@ -43622,15 +44934,14 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
* array part pointer to avoid any GC interference while the
* array part is populated.
*/
- duk_push_string(ctx, c_filename);
+ duk_push_string(thr, c_filename);
arr_size += 2;
}
+ /* XXX: uninitialized would be OK */
DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size));
- a = duk_push_harray_with_size(ctx, (duk_uint32_t) arr_size); /* XXX: call which returns array part pointer directly */
- DUK_ASSERT(a != NULL);
- tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
- DUK_ASSERT(tv != NULL || arr_size == 0);
+ tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) arr_size);
+ DUK_ASSERT(arr_size == 0 || tv != NULL);
/* Compiler SyntaxErrors (and other errors) come first, and are
* blamed by default (not flagged "noblame").
@@ -43661,40 +44972,26 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
DUK_HSTRING_INCREF(thr, s);
tv++;
- d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
+ d = ((flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
(duk_double_t) c_line;
DUK_TVAL_SET_DOUBLE(tv, d);
tv++;
}
- /* traceback depth doesn't take into account the filename/line
- * special handling above (intentional)
+ /* Traceback depth doesn't take into account the filename/line
+ * special handling above (intentional).
*/
- 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);
-
- /* [ ... error c_filename? arr ] */
-
- 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--) {
+ for (; depth-- > 0; act = act->parent) {
duk_uint32_t pc;
duk_tval *tv_src;
- /*
- * Note: each API operation potentially resizes the callstack,
- * so be careful to re-lookup after every operation. Currently
- * these is no issue because we don't store a temporary 'act'
- * pointer at all. (This would be a non-issue if we operated
- * directly on the array part.)
- */
-
/* [... arr] */
- DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0); /* unsigned */
+ DUK_ASSERT(act != NULL); /* depth check above, assumes book-keeping is correct */
+ DUK_ASSERT_DISABLE(act->pc >= 0); /* unsigned */
/* Add function object. */
- tv_src = &(thr_callstack->callstack + i)->tv_func; /* object (function) or lightfunc */
+ tv_src = &act->tv_func; /* object (function) or lightfunc */
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src));
DUK_TVAL_SET_TVAL(tv, tv_src);
DUK_TVAL_INCREF(thr, tv);
@@ -43705,26 +45002,33 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
* PC points to next instruction, find offending PC. Note that
* PC == 0 for native code.
*/
- pc = duk_hthread_get_act_prev_pc(thr_callstack, thr_callstack->callstack + i);
+ pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr_callstack, act);
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 */
- d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
+ d = ((duk_double_t) act->flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
DUK_TVAL_SET_DOUBLE(tv, d);
tv++;
}
- DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
- DUK_ASSERT(a->length == (duk_uint32_t) arr_size);
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_harray *a;
+ a = (duk_harray *) duk_known_hobject(thr, -1);
+ DUK_ASSERT(a != NULL);
+ DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
+ DUK_ASSERT(a->length == (duk_uint32_t) arr_size);
+ }
+#endif
/* [ ... error c_filename? arr ] */
if (c_filename) {
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
}
/* [ ... error arr ] */
- duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
+ duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
}
#endif /* DUK_USE_TRACEBACKS */
@@ -43733,15 +45037,13 @@ DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack,
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !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;
+DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
#if defined(DUK_USE_ASSERTIONS)
duk_int_t entry_top;
#endif
- ctx = (duk_context *) thr;
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#endif
/*
@@ -43756,37 +45058,33 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
/* 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_push_hstring(ctx, thr->compile_ctx->h_filename);
- } else if (c_filename && !noblame_fileline) {
+ duk_push_uint(thr, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
+ duk_push_hstring(thr, thr->compile_ctx->h_filename);
+ } else if (c_filename && (flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) == 0) {
/* 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_int(ctx, c_line);
- duk_push_string(ctx, c_filename);
+ duk_push_int(thr, c_line);
+ duk_push_string(thr, 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;
-
- 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_activation *act;
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;
+ depth = DUK_USE_TRACEBACK_DEPTH;
+ if (depth > thr_callstack->callstack_top) {
+ depth = thr_callstack->callstack_top;
+ }
+ for (act = thr_callstack->callstack_curr; depth-- > 0; act = act->parent) {
duk_hobject *func;
duk_uint32_t pc;
- DUK_UNREF(pc);
- act = thr_callstack->callstack + i;
- DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
-
+ DUK_ASSERT(act != NULL);
func = DUK_ACT_GET_FUNC(act);
if (func == NULL) {
/* Lightfunc, not blamed now. */
@@ -43797,17 +45095,18 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
* PC == 0 for native code.
*/
pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
+ DUK_UNREF(pc);
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 */
- duk_push_hobject(ctx, func);
+ duk_push_hobject(thr, func);
/* [ ... error func ] */
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_FILE_NAME);
- if (!duk_is_string_notsymbol(ctx, -1)) {
- duk_pop_2(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
+ if (!duk_is_string_notsymbol(thr, -1)) {
+ duk_pop_2(thr);
continue;
}
@@ -43816,16 +45115,16 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
ecma_line = 0;
#if defined(DUK_USE_PC2LINE)
if (DUK_HOBJECT_IS_COMPFUNC(func)) {
- ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc);
+ ecma_line = duk_hobject_pc2line_query(thr, -2, (duk_uint_fast32_t) pc);
} else {
/* Native function, no relevant lineNumber. */
}
#endif /* DUK_USE_PC2LINE */
- duk_push_u32(ctx, ecma_line);
+ duk_push_u32(thr, ecma_line);
/* [ ... error func fileName lineNumber ] */
- duk_replace(ctx, -3);
+ duk_replace(thr, -3);
/* [ ... error lineNumber fileName ] */
goto define_props;
@@ -43835,17 +45134,17 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
* .lineNumber (matches what we do with a _Tracedata based
* no-match lookup.
*/
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
+ duk_push_undefined(thr);
}
define_props:
/* [ ... error lineNumber fileName ] */
#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 2);
+ DUK_ASSERT(duk_get_top(thr) == entry_top + 2);
#endif
- duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */
@@ -43855,7 +45154,6 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
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
@@ -43865,26 +45163,25 @@ DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
/* [ ... error ] */
- ctx = (duk_context *) thr;
- DUK_ASSERT(duk_is_object(ctx, -1));
+ DUK_ASSERT(duk_is_object(thr, -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)));
+ (duk_tval *) duk_get_tval(thr, -1)));
- if (duk_get_prop_stridx_short(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_short(ctx, -2, DUK_STRIDX_MESSAGE);
+ if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_MESSAGE)) {
+ duk_push_sprintf(thr, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
+ duk_concat(thr, 2);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
} else {
- duk_pop(ctx);
+ duk_pop(thr);
}
DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
@@ -43894,19 +45191,17 @@ DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
*/
#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;
+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_hobject *obj, duk_small_uint_t flags) {
#if defined(DUK_USE_ASSERTIONS)
duk_int_t entry_top;
#endif
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#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);
@@ -43918,17 +45213,17 @@ DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *th
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);
+ duk__add_traceback(thr, thr_callstack, c_filename, c_line, flags);
}
#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);
+ duk__add_fileline(thr, thr_callstack, c_filename, c_line, flags);
#endif
#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == entry_top);
+ DUK_ASSERT(duk_get_top(thr) == entry_top);
#endif
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
@@ -43942,22 +45237,18 @@ DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *th
* thr_callstack: thread which should be used for generating callstack etc.
* c_filename: C __FILE__ related to the error
* c_line: C __LINE__ related to the error
- * noblame_fileline: if true, don't fileName/line as error source, otherwise use traceback
- * (needed because user code filename/line are reported but internal ones
- * are not)
- *
- * XXX: rename noblame_fileline to flags field; combine it to some existing
- * field (there are only a few call sites so this may not be worth it).
+ * flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE:
+ * if true, don't fileName/line as error source, otherwise use traceback
+ * (needed because user code filename/line are reported but internal ones
+ * are not)
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_INTERNAL void duk_err_augment_error_create(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_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
duk_hobject *obj;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr_callstack != NULL);
- DUK_ASSERT(ctx != NULL);
/* [ ... error ] */
@@ -43973,7 +45264,7 @@ DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *th
* - error value is an extensible object
*/
- obj = duk_get_hobject(ctx, -1);
+ obj = duk_get_hobject(thr, -1);
if (!obj) {
DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
return;
@@ -43988,7 +45279,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_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
+ duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, obj, flags);
} else {
DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
}
@@ -44023,32 +45314,32 @@ DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
#if defined(DUK_USE_PREFER_SIZE)
DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) {
- (void) duk_fatal((duk_context *) thr, "uncaught error");
+ (void) duk_fatal(thr, "uncaught error");
}
#endif
#if 0
DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
const char *summary;
- char buf[64];
+ char buf[DUK_USE_FATAL_MAXLEN];
- summary = duk_push_string_tval_readable((duk_context *) thr, &thr->heap->lj.value1);
+ summary = duk_push_string_tval_readable(thr, &thr->heap->lj.value1);
DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
buf[sizeof(buf) - 1] = (char) 0;
- (void) duk_fatal((duk_context *) thr, (const char *) buf);
+ (void) duk_fatal(thr, (const char *) buf);
}
#endif
#if !defined(DUK_USE_PREFER_SIZE)
DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
const char *summary;
- char buf[64];
+ char buf[DUK_USE_FATAL_MAXLEN];
- summary = duk_push_string_tval_readable_error((duk_context *) thr, &thr->heap->lj.value1);
+ summary = duk_push_string_tval_readable_error(thr, &thr->heap->lj.value1);
DUK_ASSERT(summary != NULL);
DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
buf[sizeof(buf) - 1] = (char) 0;
- (void) duk_fatal((duk_context *) thr, (const char *) buf);
+ (void) duk_fatal(thr, (const char *) buf);
}
#endif
@@ -44131,32 +45422,31 @@ 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) && \
- (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
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
- * catcher. This is usually convenient, e.g. in the case of a top-
- * level duk_pcall(), but may not always be desirable. Perhaps add an
- * argument to treat them as catchers?
+ /* As noted above, a protected API call won't be counted as a
+ * catcher. This is usually convenient, e.g. in the case of a top-
+ * level duk_pcall(), but may not always be desirable. Perhaps add
+ * an argument to treat them as catchers?
*/
- duk_size_t i;
+ duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
- while (thr != NULL) {
- for (i = 0; i < thr->catchstack_top; i++) {
- duk_catcher *cat = thr->catchstack + i;
- if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
- return 1; /* all we need to know */
+ for (; thr != NULL; thr = thr->resumer) {
+ for (act = thr->callstack_curr; act != NULL; act = act->parent) {
+ for (cat = act->cat; cat != NULL; cat = cat->parent) {
+ if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
+ return 1; /* all we need to know */
+ }
}
}
- thr = thr->resumer;
}
return 0;
}
-#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
+#endif /* DUK_USE_DEBUGGER_SUPPORT */
/*
* Get prototype object for an integer error code.
@@ -44187,10 +45477,8 @@ DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_er
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t fatal;
+ duk_bool_t uncaught;
duk_tval *tv_obj;
/* If something is thrown with the debugger attached and nobody will
@@ -44228,14 +45516,14 @@ DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
return;
}
- fatal = !duk__have_active_catcher(thr);
+ uncaught = !duk__have_active_catcher(thr);
/* Debugger code expects the value at stack top. This also serves
* as a backup: we need to store/restore the longjmp state because
* when the debugger is paused Eval commands may be executed and
* they can arbitrarily clobber the longjmp state.
*/
- duk_push_tval(ctx, tv_obj);
+ duk_push_tval(thr, tv_obj);
/* Store and reset longjmp state. */
DUK_ASSERT_LJSTATE_SET(thr->heap);
@@ -44248,33 +45536,33 @@ DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
/* Report it to the debug client */
DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
- duk_debug_send_throw(thr, fatal);
+ duk_debug_send_throw(thr, uncaught);
#endif
-#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
- if (fatal) {
- DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp"));
- duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
+ if (uncaught) {
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_UNCAUGHT_ERROR) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by uncaught error"));
+ duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
+ }
+ } else {
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_CAUGHT_ERROR) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by caught error"));
+ duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
+ }
}
-#endif
/* Restore longjmp state. */
DUK_ASSERT_LJSTATE_UNSET(thr->heap);
thr->heap->lj.type = DUK_LJ_TYPE_THROW;
- tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv_obj = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, tv_obj);
DUK_TVAL_INCREF(thr, tv_obj);
DUK_ASSERT_LJSTATE_SET(thr->heap);
- duk_pop(ctx);
+ duk_pop(thr);
}
-#else /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
-DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
- DUK_UNREF(thr);
-}
-#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
#endif /* DUK_USE_DEBUGGER_SUPPORT */
/*
@@ -44324,8 +45612,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code,
#else
DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
#endif
- duk_context *ctx = (duk_context *) thr;
-
#if defined(DUK_USE_VERBOSE_ERRORS)
DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
(long) code, (const char *) msg,
@@ -44335,7 +45621,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
/* Even though nested call is possible because we throw an error when
* trying to create an error, the potential errors must happen before
@@ -44361,10 +45646,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
duk_tval tv_val;
duk_hobject *h_err;
-#if 0 /* XXX: not always true because the second throw may come from a different coroutine */
- DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11);
-#endif
- thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
thr->heap->creating_error = 0;
h_err = thr->builtins[DUK_BIDX_DOUBLE_ERROR];
@@ -44381,30 +45662,27 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
/* No augmentation to avoid any allocations or side effects. */
} else {
- /* Allow headroom for calls during error handling (see GH-191).
- * We allow space for 10 additional recursions, with one extra
- * for, e.g. a print() call at the deepest level.
+ /* Prevent infinite recursion. Extra call stack and C
+ * recursion headroom (see GH-191) is added for augmentation.
+ * That is now signalled by heap->augmenting error and taken
+ * into account in call handling without an explicit limit bump.
*/
-#if 0 /* XXX: not always true, second throw may come from a different coroutine */
- DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX);
-#endif
- thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11;
thr->heap->creating_error = 1;
- duk_require_stack(ctx, 1);
+ duk_require_stack(thr, 1);
/* XXX: usually unnecessary '%s' formatting here, but cannot
* use 'msg' as a format string directly.
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
- duk_push_error_object_raw(ctx,
+ duk_push_error_object_raw(thr,
code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
filename,
line,
"%s",
(const char *) msg);
#else
- duk_push_error_object_raw(ctx,
+ duk_push_error_object_raw(thr,
code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
NULL,
0,
@@ -44419,12 +45697,11 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
*/
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk_err_augment_error_throw(thr);
#endif
- duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1));
- thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
+ duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
thr->heap->creating_error = 0;
/* Error is now created and we assume no errors can occur any
@@ -44454,8 +45731,6 @@ DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)
*/
DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
- duk_context *ctx = (duk_context *) thr;
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(rc < 0);
@@ -44469,7 +45744,7 @@ DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t r
* minimal: they're only really useful for low memory targets.
*/
- duk_error_raw(ctx, -rc, NULL, 0, "error (rc %ld)", (long) rc);
+ duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc);
DUK_UNREACHABLE();
}
/*
@@ -44607,12 +45882,6 @@ DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
/*
* duk_hbuffer operations such as resizing and inserting/appending data to
* a dynamic buffer.
- *
- * Append operations append to the end of the buffer and they are relatively
- * efficient: the buffer is grown with a "spare" part relative to the buffer
- * size to minimize reallocations. Insert operations need to move existing
- * data forward in the buffer with memmove() and are not very efficient.
- * They are used e.g. by the regexp compiler to "backpatch" regexp bytecode.
*/
/* #include duk_internal.h -> already included */
@@ -44742,19 +46011,43 @@ DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) {
/* Currently nothing to free */
} else if (DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ duk_activation *act;
+
DUK_FREE(heap, t->valstack);
- DUK_FREE(heap, t->callstack);
- DUK_FREE(heap, t->catchstack);
+
/* Don't free h->resumer because it exists in the heap.
* Callstack entries also contain function pointers which
- * are not freed for the same reason.
+ * are not freed for the same reason. They are decref
+ * finalized and the targets are freed if necessary based
+ * on their refcount (or reachability).
*/
+ for (act = t->callstack_curr; act != NULL;) {
+ duk_activation *act_next;
+ duk_catcher *cat;
+
+ for (cat = act->cat; cat != NULL;) {
+ duk_catcher *cat_next;
+
+ cat_next = cat->parent;
+ DUK_FREE(heap, (void *) cat);
+ cat = cat_next;
+ }
+
+ act_next = act->parent;
+ DUK_FREE(heap, (void *) act);
+ act = act_next;
+ }
/* XXX: with 'caller' property the callstack would need
* to be unwound to update the 'caller' properties of
* functions in the callstack.
*/
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
+ duk_hboundfunc *f = (duk_hboundfunc *) h;
+
+ DUK_FREE(heap, f->args);
}
+
DUK_FREE(heap, (void *) h);
}
@@ -44820,6 +46113,63 @@ DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
* after this call.
*/
+#if defined(DUK_USE_CACHE_ACTIVATION)
+DUK_LOCAL duk_size_t duk__heap_free_activation_freelist(duk_heap *heap) {
+ duk_activation *act;
+ duk_activation *act_next;
+ duk_size_t count_act = 0;
+
+ for (act = heap->activation_free; act != NULL;) {
+ act_next = act->parent;
+ DUK_FREE(heap, (void *) act);
+ act = act_next;
+#if defined(DUK_USE_DEBUG)
+ count_act++;
+#endif
+ }
+ heap->activation_free = NULL; /* needed when called from mark-and-sweep */
+ return count_act;
+}
+#endif /* DUK_USE_CACHE_ACTIVATION */
+
+#if defined(DUK_USE_CACHE_CATCHER)
+DUK_LOCAL duk_size_t duk__heap_free_catcher_freelist(duk_heap *heap) {
+ duk_catcher *cat;
+ duk_catcher *cat_next;
+ duk_size_t count_cat = 0;
+
+ for (cat = heap->catcher_free; cat != NULL;) {
+ cat_next = cat->parent;
+ DUK_FREE(heap, (void *) cat);
+ cat = cat_next;
+#if defined(DUK_USE_DEBUG)
+ count_cat++;
+#endif
+ }
+ heap->catcher_free = NULL; /* needed when called from mark-and-sweep */
+
+ return count_cat;
+}
+#endif /* DUK_USE_CACHE_CATCHER */
+
+DUK_INTERNAL void duk_heap_free_freelists(duk_heap *heap) {
+ duk_size_t count_act = 0;
+ duk_size_t count_cat = 0;
+
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ count_act = duk__heap_free_activation_freelist(heap);
+#endif
+#if defined(DUK_USE_CACHE_CATCHER)
+ count_cat = duk__heap_free_catcher_freelist(heap);
+#endif
+ DUK_UNREF(heap);
+ DUK_UNREF(count_act);
+ DUK_UNREF(count_cat);
+
+ DUK_D(DUK_DPRINT("freed %ld activation freelist entries, %ld catcher freelist entries",
+ (long) count_act, (long) count_cat));
+}
+
DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
duk_heaphdr *curr;
duk_heaphdr *next;
@@ -45025,6 +46375,9 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
* are on the heap allocated list.
*/
+ DUK_D(DUK_DPRINT("freeing temporary freelists"));
+ duk_heap_free_freelists(heap);
+
DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap));
duk__free_allocated(heap);
@@ -45181,8 +46534,8 @@ DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
/* XXX: this may now fail, and is not handled correctly */
duk_hthread_create_builtin_objects(thr);
- /* default prototype (Note: 'thr' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
+ /* default prototype */
+ DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
return 1;
}
@@ -45298,6 +46651,7 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK__DUMPSZ(duk_hbufobj);
#endif
+ DUK__DUMPSZ(duk_hproxy);
DUK__DUMPSZ(duk_hbuffer);
DUK__DUMPSZ(duk_hbuffer_fixed);
DUK__DUMPSZ(duk_hbuffer_dynamic);
@@ -45535,6 +46889,12 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
res->currently_finalizing = NULL;
#endif
#endif
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ res->activation_free = NULL;
+#endif
+#if defined(DUK_USE_CACHE_CATCHER)
+ res->catcher_free = NULL;
+#endif
res->heap_thread = NULL;
res->curr_thread = NULL;
res->heap_object = NULL;
@@ -45565,7 +46925,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
res->dbg_write_flush_cb = NULL;
res->dbg_request_cb = NULL;
res->dbg_udata = NULL;
- res->dbg_step_thread = NULL;
+ res->dbg_pause_act = NULL;
#endif
#endif /* DUK_USE_EXPLICIT_NULL_INIT */
@@ -45727,14 +47087,14 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
- res->rnd_state = (duk_uint32_t) DUK_USE_DATE_GET_NOW((duk_context *) res->heap_thread);
+ res->rnd_state = (duk_uint32_t) duk_time_get_ecmascript_time(res->heap_thread);
duk_util_tinyrandom_prepare_seed(res->heap_thread);
#else
- res->rnd_state[0] = (duk_uint64_t) DUK_USE_DATE_GET_NOW((duk_context *) res->heap_thread);
+ res->rnd_state[0] = (duk_uint64_t) duk_time_get_ecmascript_time(res->heap_thread);
DUK_ASSERT(res->rnd_state[1] == 0); /* Not filled here, filled in by seed preparation. */
#if 0 /* Manual test values matching misc/xoroshiro128plus_test.c. */
- res->rnd_state[0] = 0xdeadbeef12345678ULL;
- res->rnd_state[1] = 0xcafed00d12345678ULL;
+ res->rnd_state[0] = DUK_U64_CONSTANT(0xdeadbeef12345678);
+ res->rnd_state[1] = DUK_U64_CONSTANT(0xcafed00d12345678);
#endif
duk_util_tinyrandom_prepare_seed(res->heap_thread);
/* Mix in heap pointer: this ensures that if two Duktape heaps are
@@ -45831,21 +47191,19 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
*/
#if defined(DUK_USE_FINALIZER_TORTURE)
-DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_context *ctx) {
+DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_hthread *thr) {
DUK_DD(DUK_DDPRINT("fake global torture finalizer executed"));
/* Require a lot of stack to force a value stack grow/shrink. */
- duk_require_stack(ctx, 100000);
+ duk_require_stack(thr, 100000);
- /* Force a reallocation with pointer change for value, call, and
- * catch stacks to maximize side effects.
+ /* Force a reallocation with pointer change for value stack
+ * to maximize side effects.
*/
- duk_hthread_valstack_torture_realloc((duk_hthread *) ctx);
- duk_hthread_callstack_torture_realloc((duk_hthread *) ctx);
- duk_hthread_catchstack_torture_realloc((duk_hthread *) ctx);
+ duk_hthread_valstack_torture_realloc(thr);
/* Inner function call, error throw. */
- duk_eval_string_noresult(ctx,
+ duk_eval_string_noresult(thr,
"(function dummy() {\n"
" dummy.prototype = null; /* break reference loop */\n"
" try {\n"
@@ -45870,19 +47228,20 @@ DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_context *ctx) {
DUK_LOCAL void duk__run_global_torture_finalizer(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
- /* Avoid fake finalization when callstack limit has been reached.
- * Otherwise a callstack limit error will be created, then refzero'ed.
+ /* Avoid fake finalization when callstack limit is near. Otherwise
+ * a callstack limit error will be created, then refzero'ed. The
+ * +5 headroom is conservative.
*/
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
- thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
- DUK_D(DUK_DPRINT("skip global torture finalizer because of call recursion or call stack size limit"));
+ if (thr->heap->call_recursion_depth + 5 >= thr->heap->call_recursion_limit ||
+ thr->callstack_top + 5 >= DUK_USE_CALLSTACK_LIMIT) {
+ DUK_D(DUK_DPRINT("skip global torture finalizer, too little headroom for call recursion or call stack size"));
return;
}
/* Run fake finalizer. Avoid creating unnecessary garbage. */
- duk_push_c_function((duk_context *) thr, duk__fake_global_finalizer, 0 /*nargs*/);
- (void) duk_pcall((duk_context *) thr, 0 /*nargs*/);
- duk_pop((duk_context *) thr);
+ duk_push_c_function(thr, duk__fake_global_finalizer, 0 /*nargs*/);
+ (void) duk_pcall(thr, 0 /*nargs*/);
+ duk_pop(thr);
}
#endif /* DUK_USE_FINALIZER_TORTURE */
@@ -45964,8 +47323,6 @@ DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(heap->heap_thread->valstack != NULL);
- DUK_ASSERT(heap->heap_thread->callstack != NULL);
- DUK_ASSERT(heap->heap_thread->catchstack != NULL);
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_ASSERT(heap->refzero_list == NULL);
#endif
@@ -46160,11 +47517,8 @@ DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) {
* left on the finalizer stack).
*/
-DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) {
- duk_hthread *thr;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__finalize_helper(duk_hthread *thr, void *udata) {
+ DUK_ASSERT(thr != NULL);
DUK_UNREF(udata);
DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
@@ -46181,11 +47535,11 @@ DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) {
* caller must ensure that this function is not called if the target is
* a Proxy.
*/
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
- duk_dup_m2(ctx);
- duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
+ duk_dup_m2(thr);
+ duk_push_boolean(thr, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
DUK_DDD(DUK_DDDPRINT("calling finalizer"));
- duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
+ duk_call(thr, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
DUK_DDD(DUK_DDDPRINT("finalizer returned successfully"));
return 0;
@@ -46196,7 +47550,7 @@ DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) {
}
DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) {
- duk_context *ctx;
+ duk_hthread *thr;
duk_ret_t rc;
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t entry_top;
@@ -46206,12 +47560,12 @@ DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
- ctx = (duk_context *) heap->heap_thread;
+ thr = heap->heap_thread;
DUK_ASSERT(obj != NULL);
DUK_ASSERT_VALSTACK_SPACE(heap->heap_thread, 1);
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#endif
/*
* Get and call the finalizer. All of this must be wrapped
@@ -46236,30 +47590,32 @@ DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) {
#endif
DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
+#if defined(DUK_USE_ES6_PROXY)
+ if (DUK_HOBJECT_IS_PROXY(obj)) {
/* This may happen if duk_set_finalizer() or Duktape.fin() is
* called for a Proxy object. In such cases the fast finalizer
* flag will be set on the Proxy, not the target, and neither
* will be finalized.
*/
- DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call"));
+ DUK_D(DUK_DPRINT("object is a Proxy, skip finalizer call"));
return;
}
+#endif /* DUK_USE_ES6_PROXY */
- duk_push_hobject(ctx, obj); /* this also increases refcount by one */
- rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
- DUK_ASSERT_TOP(ctx, entry_top + 2); /* duk_safe_call discipline */
+ duk_push_hobject(thr, obj); /* this also increases refcount by one */
+ rc = duk_safe_call(thr, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
+ DUK_ASSERT_TOP(thr, entry_top + 2); /* duk_safe_call discipline */
if (rc != DUK_EXEC_SUCCESS) {
/* Note: we ask for one return value from duk_safe_call to get this
* error debugging here.
*/
DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
- (void *) obj, (duk_tval *) duk_get_tval(ctx, -1)));
+ (void *) obj, (duk_tval *) duk_get_tval(thr, -1)));
}
- duk_pop_2(ctx); /* -> [...] */
+ duk_pop_2(thr); /* -> [...] */
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
}
#else /* DUK_USE_FINALIZER_SUPPORT */
@@ -46395,7 +47751,9 @@ DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t
/* #include duk_internal.h -> already included */
DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
+DUK_LOCAL_DECL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h);
DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
+DUK_LOCAL_DECL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count);
/*
* Marking functions for heap types: mark children recursively.
@@ -46425,7 +47783,7 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
if (key == NULL) {
continue;
}
- duk__mark_heaphdr(heap, (duk_heaphdr *) key);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) key);
if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
@@ -46451,11 +47809,14 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
}
DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
+ /* XXX: reorg, more common first */
if (DUK_HOBJECT_IS_COMPFUNC(h)) {
duk_hcompfunc *f = (duk_hcompfunc *) h;
duk_tval *tv, *tv_end;
duk_hobject **fn, **fn_end;
+ DUK_ASSERT_HCOMPFUNC_VALID(f);
+
/* 'data' is reachable through every compiled function which
* contains a reference.
*/
@@ -46475,19 +47836,13 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
fn_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
while (fn < fn_end) {
- duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) *fn);
fn++;
}
} else {
/* May happen in some out-of-memory corner cases. */
DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking"));
}
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
- duk_hbufobj *b = (duk_hbufobj *) h;
- duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
- duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop);
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
} else if (DUK_HOBJECT_IS_DECENV(h)) {
duk_hdecenv *e = (duk_hdecenv *) h;
DUK_ASSERT_HDECENV_VALID(e);
@@ -46496,32 +47851,52 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
} else if (DUK_HOBJECT_IS_OBJENV(h)) {
duk_hobjenv *e = (duk_hobjenv *) h;
DUK_ASSERT_HOBJENV_VALID(e);
- duk__mark_heaphdr(heap, (duk_heaphdr *) e->target);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) e->target);
+#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
+ } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
+ duk_hbufobj *b = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(b);
+ duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
+ duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop);
+#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
+ duk_hboundfunc *f = (duk_hboundfunc *) h;
+ DUK_ASSERT_HBOUNDFUNC_VALID(f);
+ duk__mark_tval(heap, &f->target);
+ duk__mark_tval(heap, &f->this_binding);
+ duk__mark_tvals(heap, f->args, f->nargs);
+#if defined(DUK_USE_ES6_PROXY)
+ } else if (DUK_HOBJECT_IS_PROXY(h)) {
+ duk_hproxy *p = (duk_hproxy *) h;
+ DUK_ASSERT_HPROXY_VALID(p);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->target);
+ duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->handler);
+#endif /* DUK_USE_ES6_PROXY */
} else if (DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ duk_activation *act;
duk_tval *tv;
+ DUK_ASSERT_HTHREAD_VALID(t);
+
tv = t->valstack;
while (tv < t->valstack_top) {
duk__mark_tval(heap, tv);
tv++;
}
- for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
- duk_activation *act = t->callstack + i;
+ for (act = t->callstack_curr; act != NULL; act = act->parent) {
duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
#endif
- }
-
#if 0 /* nothing now */
- for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
- duk_catcher *cat = t->catchstack + i;
- }
+ for (cat = act->cat; cat != NULL; cat = cat->parent) {
+ }
#endif
+ }
duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
@@ -46543,22 +47918,30 @@ DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
(void *) h,
(h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
+
+ /* XXX: add non-null variant? */
if (h == NULL) {
return;
}
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY(h)) {
- DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h));
- return;
- }
-#endif
+
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h) || DUK_HEAPHDR_HAS_REACHABLE(h));
+
#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
- h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */
+ if (!DUK_HEAPHDR_HAS_READONLY(h)) {
+ h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */
+ }
#endif
if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
return;
}
+#if defined(DUK_USE_ROM_OBJECTS)
+ /* READONLY objects always have REACHABLE set, so the check above
+ * will prevent READONLY objects from being marked here.
+ */
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h));
+#endif
+
DUK_HEAPHDR_SET_REACHABLE(h);
if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
@@ -46596,10 +47979,35 @@ DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
return;
}
if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv));
+ duk_heaphdr *h;
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ duk__mark_heaphdr_nonnull(heap, h);
}
}
+DUK_LOCAL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count) {
+ DUK_ASSERT(count == 0 || tv != NULL);
+
+ while (count-- > 0) {
+ if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
+ duk_heaphdr *h;
+ h = DUK_TVAL_GET_HEAPHDR(tv);
+ DUK_ASSERT(h != NULL);
+ duk__mark_heaphdr_nonnull(heap, h);
+ }
+ tv++;
+ }
+}
+
+/* Mark any duk_heaphdr type, caller guarantees a non-NULL pointer. */
+DUK_LOCAL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h) {
+ /* For now, just call the generic handler. Change when call sites
+ * are changed too.
+ */
+ duk__mark_heaphdr(heap, h);
+}
+
/*
* Mark the heap.
*/
@@ -46690,7 +48098,7 @@ DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
hdr = heap->heap_allocated;
while (hdr != NULL) {
if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
- duk__mark_heaphdr(heap, hdr);
+ duk__mark_heaphdr_nonnull(heap, hdr);
}
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
@@ -46715,7 +48123,7 @@ DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
hdr = heap->finalize_list;
while (hdr != NULL) {
- duk__mark_heaphdr(heap, hdr);
+ duk__mark_heaphdr_nonnull(heap, hdr);
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
#if defined(DUK_USE_DEBUG)
count_finalize_list++;
@@ -46753,6 +48161,8 @@ DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t
#else
DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
#endif
+ DUK_ASSERT(hdr != NULL);
+
if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
return;
@@ -46764,7 +48174,7 @@ DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
hdr->h_assert_refcount--; /* Same node visited twice. */
#endif
- duk__mark_heaphdr(heap, hdr);
+ duk__mark_heaphdr_nonnull(heap, hdr);
#if defined(DUK_USE_DEBUG)
(*count)++;
@@ -46972,7 +48382,7 @@ DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep
* Sweep heap.
*/
-DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) {
+DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_t *out_count_keep) {
duk_heaphdr *prev; /* last element that was left in the heap */
duk_heaphdr *curr;
duk_heaphdr *next;
@@ -46983,7 +48393,6 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
#endif
duk_size_t count_keep = 0;
- DUK_UNREF(flags);
DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
prev = NULL;
@@ -47063,6 +48472,18 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
prev = curr;
}
+ /*
+ * Shrink check for value stacks here. We're inside
+ * ms_prevent_count protection which prevents recursive
+ * mark-and-sweep and refzero finalizers, so there are
+ * no side effects that would affect the heap lists.
+ */
+ if (DUK_HEAPHDR_IS_OBJECT(curr) && DUK_HOBJECT_IS_THREAD((duk_hobject *) curr)) {
+ duk_hthread *thr_curr = (duk_hthread *) curr;
+ DUK_DD(DUK_DDPRINT("value stack shrink check for thread: %!O", curr));
+ duk_valstack_shrink_check_nothrow(thr_curr, flags & DUK_MS_FLAG_EMERGENCY /*snug*/);
+ }
+
DUK_HEAPHDR_CLEAR_REACHABLE(curr);
/* Keep FINALIZED if set, used if rescue decisions are postponed. */
/* Keep FINALIZABLE for objects on finalize_list. */
@@ -47137,13 +48558,13 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
* Compaction is assumed to never throw an error.
*/
-DUK_LOCAL int duk__protected_compact_object(duk_context *ctx, void *udata) {
+DUK_LOCAL int duk__protected_compact_object(duk_hthread *thr, void *udata) {
duk_hobject *obj;
- /* XXX: for threads, compact value stack, call stack, catch stack? */
+ /* XXX: for threads, compact stacks? */
DUK_UNREF(udata);
- obj = duk_known_hobject(ctx, -1);
- duk_hobject_compact_props((duk_hthread *) ctx, obj);
+ obj = duk_known_hobject(thr, -1);
+ duk_hobject_compact_props(thr, obj);
return 0;
}
@@ -47176,9 +48597,9 @@ DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_he
#endif
DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
- duk_push_hobject((duk_context *) thr, obj);
+ duk_push_hobject(thr, obj);
/* XXX: disable error handlers for duration of compaction? */
- duk_safe_call((duk_context *) thr, duk__protected_compact_object, NULL, 1, 0);
+ duk_safe_call(thr, duk__protected_compact_object, NULL, 1, 0);
#if defined(DUK_USE_DEBUG)
new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
@@ -47371,6 +48792,56 @@ DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) {
#endif /* DUK_USE_ASSERTIONS */
/*
+ * Stats dump.
+ */
+
+#if defined(DUK_USE_DEBUG)
+DUK_LOCAL void duk__dump_stats(duk_heap *heap) {
+ DUK_D(DUK_DPRINT("stats executor: opcodes=%ld, interrupt=%ld, throw=%ld",
+ (long) heap->stats_exec_opcodes, (long) heap->stats_exec_interrupt,
+ (long) heap->stats_exec_throw));
+ DUK_D(DUK_DPRINT("stats call: all=%ld, tailcall=%ld, ecmatoecma=%ld",
+ (long) heap->stats_call_all, (long) heap->stats_call_tailcall,
+ (long) heap->stats_call_ecmatoecma));
+ DUK_D(DUK_DPRINT("stats safecall: all=%ld, nothrow=%ld, throw=%ld",
+ (long) heap->stats_safecall_all, (long) heap->stats_safecall_nothrow,
+ (long) heap->stats_safecall_throw));
+ DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld",
+ (long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count,
+ (long) heap->stats_ms_emergency_count));
+ DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, resize_check=%ld, resize_grow=%ld, resize_shrink=%ld",
+ (long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss,
+ (long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow,
+ (long) heap->stats_strtab_resize_shrink));
+ DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld",
+ (long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array));
+ DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld",
+ (long) heap->stats_getownpropdesc_count, (long) heap->stats_getownpropdesc_hit,
+ (long) heap->stats_getownpropdesc_miss));
+ DUK_D(DUK_DPRINT("stats getpropdesc: count=%ld, hit=%ld, miss=%ld",
+ (long) heap->stats_getpropdesc_count, (long) heap->stats_getpropdesc_hit,
+ (long) heap->stats_getpropdesc_miss));
+ DUK_D(DUK_DPRINT("stats getprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
+ "bufferidx=%ld, bufferlen=%ld, stringidx=%ld, stringlen=%ld, "
+ "proxy=%ld, arguments=%ld",
+ (long) heap->stats_getprop_all, (long) heap->stats_getprop_arrayidx,
+ (long) heap->stats_getprop_bufobjidx, (long) heap->stats_getprop_bufferidx,
+ (long) heap->stats_getprop_bufferlen, (long) heap->stats_getprop_stringidx,
+ (long) heap->stats_getprop_stringlen, (long) heap->stats_getprop_proxy,
+ (long) heap->stats_getprop_arguments));
+ DUK_D(DUK_DPRINT("stats putprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
+ "bufferidx=%ld, proxy=%ld",
+ (long) heap->stats_putprop_all, (long) heap->stats_putprop_arrayidx,
+ (long) heap->stats_putprop_bufobjidx, (long) heap->stats_putprop_bufferidx,
+ (long) heap->stats_putprop_proxy));
+ DUK_D(DUK_DPRINT("stats getvar: all=%ld",
+ (long) heap->stats_getvar_all));
+ DUK_D(DUK_DPRINT("stats putvar: all=%ld",
+ (long) heap->stats_putvar_all));
+}
+#endif /* DUK_USE_DEBUG */
+
+/*
* Main mark-and-sweep function.
*
* 'flags' represents the features requested by the caller. The current
@@ -47385,6 +48856,13 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags
duk_size_t tmp;
#endif
+ DUK_STATS_INC(heap, stats_ms_try_count);
+#if defined(DUK_USE_DEBUG)
+ if (flags & DUK_MS_FLAG_EMERGENCY) {
+ DUK_STATS_INC(heap, stats_ms_emergency_count);
+ }
+#endif
+
/* If debugger is paused, garbage collection is disabled by default.
* This is achieved by bumping ms_prevent_count when becoming paused.
*/
@@ -47396,6 +48874,7 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags
*/
if (heap->ms_prevent_count != 0) {
DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep"));
+ DUK_STATS_INC(heap, stats_ms_skip_count);
return;
}
DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */
@@ -47407,8 +48886,6 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags
*/
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(heap->heap_thread->valstack != NULL);
- DUK_ASSERT(heap->heap_thread->callstack != NULL);
- DUK_ASSERT(heap->heap_thread->catchstack != NULL);
DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
(unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags)));
@@ -47449,6 +48926,15 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags
heap->ms_running = 1;
/*
+ * Free activation/catcher freelists on every mark-and-sweep for now.
+ * This is an initial rough draft; ideally we'd keep count of the
+ * freelist size and free only excess entries.
+ */
+
+ DUK_D(DUK_DPRINT("freeing temporary freelists"));
+ duk_heap_free_freelists(heap);
+
+ /*
* Mark roots, hoping that recursion limit is not normally hit.
* If recursion limit is hit, run additional reachability rounds
* starting from "temproots" until marking is complete.
@@ -47591,6 +49077,14 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags
#endif
/*
+ * Stats dump
+ */
+
+#if defined(DUK_USE_DEBUG)
+ duk__dump_stats(heap);
+#endif
+
+ /*
* Finalize objects in the finalization work list. Finalized
* objects are queued back to heap_allocated with FINALIZED set.
*
@@ -47679,7 +49173,9 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
*/
#if defined(DUK_USE_GC_TORTURE)
- /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */
+ /* Simulate alloc failure on every alloc, except when mark-and-sweep
+ * is running.
+ */
if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
res = NULL;
@@ -47689,7 +49185,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
#endif
res = heap->alloc_func(heap->heap_udata, size);
if (DUK_LIKELY(res || size == 0)) {
- /* for zero size allocations NULL is allowed */
+ /* For zero size allocations NULL is allowed. */
return res;
}
#if defined(DUK_USE_GC_TORTURE)
@@ -47804,7 +49300,9 @@ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t ne
*/
#if defined(DUK_USE_GC_TORTURE)
- /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
+ /* Simulate alloc failure on every realloc, except when mark-and-sweep
+ * is running.
+ */
if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
res = NULL;
@@ -47814,7 +49312,7 @@ DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t ne
#endif
res = heap->realloc_func(heap->heap_udata, ptr, newsize);
if (DUK_LIKELY(res || newsize == 0)) {
- /* for zero size allocations NULL is allowed */
+ /* For zero size allocations NULL is allowed. */
return res;
}
#if defined(DUK_USE_GC_TORTURE)
@@ -47886,7 +49384,9 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
*/
#if defined(DUK_USE_GC_TORTURE)
- /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
+ /* Simulate alloc failure on every realloc, except when mark-and-sweep
+ * is running.
+ */
if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
res = NULL;
@@ -47896,7 +49396,7 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
#endif
res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
if (DUK_LIKELY(res || newsize == 0)) {
- /* for zero size allocations NULL is allowed */
+ /* For zero size allocations NULL is allowed. */
return res;
}
#if defined(DUK_USE_GC_TORTURE)
@@ -47925,12 +49425,12 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
duk_small_uint_t flags;
-#if defined(DUK_USE_ASSERTIONS)
- void *ptr_pre; /* ptr before mark-and-sweep */
+#if defined(DUK_USE_DEBUG)
+ void *ptr_pre;
void *ptr_post;
#endif
-#if defined(DUK_USE_ASSERTIONS)
+#if defined(DUK_USE_DEBUG)
ptr_pre = cb(heap, ud);
#endif
flags = 0;
@@ -47939,11 +49439,10 @@ DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr
}
duk_heap_mark_and_sweep(heap, flags);
-#if defined(DUK_USE_ASSERTIONS)
+#if defined(DUK_USE_DEBUG)
ptr_post = cb(heap, ud);
if (ptr_pre != ptr_post) {
- /* useful for debugging */
- DUK_DD(DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p",
+ DUK_DD(DUK_DDPRINT("realloc base pointer changed by mark-and-sweep: %p -> %p",
(void *) ptr_pre, (void *) ptr_post));
}
#endif
@@ -48200,6 +49699,15 @@ DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
* actual references.
*/
+DUK_LOCAL void duk__decref_tvals_norz(duk_hthread *thr, duk_tval *tv, duk_idx_t count) {
+ DUK_ASSERT(count == 0 || tv != NULL);
+
+ while (count-- > 0) {
+ DUK_TVAL_DECREF_NORZ(thr, tv);
+ tv++;
+ }
+}
+
DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h) {
duk_hthread *thr;
duk_uint_fast32_t i;
@@ -48277,11 +49785,14 @@ DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject
/* Slow path: special object, start bit checks from most likely. */
+ /* XXX: reorg, more common first */
if (DUK_HOBJECT_IS_COMPFUNC(h)) {
duk_hcompfunc *f = (duk_hcompfunc *) h;
duk_tval *tv, *tv_end;
duk_hobject **funcs, **funcs_end;
+ DUK_ASSERT_HCOMPFUNC_VALID(f);
+
if (DUK_LIKELY(DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL)) {
tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
@@ -48321,34 +49832,49 @@ DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
} else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
duk_hbufobj *b = (duk_hbufobj *) h;
+ DUK_ASSERT_HBUFOBJ_VALID(b);
DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf);
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop);
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
+ } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
+ duk_hboundfunc *f = (duk_hboundfunc *) h;
+ DUK_ASSERT_HBOUNDFUNC_VALID(f);
+ DUK_TVAL_DECREF_NORZ(thr, &f->target);
+ DUK_TVAL_DECREF_NORZ(thr, &f->this_binding);
+ duk__decref_tvals_norz(thr, f->args, f->nargs);
+#if defined(DUK_USE_ES6_PROXY)
+ } else if (DUK_HOBJECT_IS_PROXY(h)) {
+ duk_hproxy *p = (duk_hproxy *) h;
+ DUK_ASSERT_HPROXY_VALID(p);
+ DUK_HOBJECT_DECREF_NORZ(thr, p->target);
+ DUK_HOBJECT_DECREF_NORZ(thr, p->handler);
+#endif /* DUK_USE_ES6_PROXY */
} else if (DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
+ duk_activation *act;
duk_tval *tv;
+ DUK_ASSERT_HTHREAD_VALID(t);
+
tv = t->valstack;
while (tv < t->valstack_top) {
DUK_TVAL_DECREF_NORZ(thr, tv);
tv++;
}
- for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
- duk_activation *act = t->callstack + i;
+ for (act = t->callstack_curr; act != NULL; act = act->parent) {
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act));
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env);
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env);
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller);
#endif
- }
-
#if 0 /* nothing now */
- for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
- duk_catcher *cat = t->catchstack + i;
- }
+ for (cat = act->cat; cat != NULL; cat = cat->parent) {
+ }
#endif
+ }
+
for (i = 0; i < DUK_NUM_BUILTINS; i++) {
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]);
@@ -48496,7 +50022,7 @@ DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hobject(duk_heap *heap, duk_hobj
/* This finalizer check MUST BE side effect free. It should also be
* as fast as possible because it's applied to every object freed.
*/
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr) != 0U)) {
/* Special case: FINALIZED may be set if mark-and-sweep queued
* object for finalization, the finalizer was executed (and
* FINALIZED set), mark-and-sweep hasn't yet processed the
@@ -49513,11 +51039,10 @@ DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap,
* checks will be false.
*/
if (DUK_UNLIKELY(data[0] >= 0x80U)) {
- if (data[0] == 0xffU) {
+ if (data[0] <= 0x81) {
DUK_HSTRING_SET_SYMBOL(res);
+ } else if (data[0] == 0x82U || data[0] == 0xffU) {
DUK_HSTRING_SET_HIDDEN(res);
- } else if (data[0] <= 0xbf) {
- /* Check equivalent to: (data[0] & 0xc0U) == 0x80U. */
DUK_HSTRING_SET_SYMBOL(res);
}
}
@@ -49529,6 +51054,12 @@ DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap,
* The flag is set lazily for RAM strings.
*/
DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
+
+#if defined(DUK_USE_HSTRING_LAZY_CLEN)
+ /* Charlen initialized to 0, updated on-the-fly. */
+#else
+ duk_hstring_init_charlen(res); /* Also sets ASCII flag. */
+#endif
}
DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld",
@@ -49572,6 +51103,8 @@ DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) {
DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */
DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
+ DUK_STATS_INC(heap, stats_strtab_resize_grow);
+
new_st_size = heap->st_size << 1U;
DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */
@@ -49688,6 +51221,8 @@ DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) {
DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */
DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
+ DUK_STATS_INC(heap, stats_strtab_resize_shrink);
+
new_st_size = heap->st_size >> 1U;
/* Combine two buckets into a single one. When we shrink, one hash
@@ -49758,8 +51293,10 @@ DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap)
DUK_ASSERT(heap->strtable != NULL);
#endif
+ DUK_STATS_INC(heap, stats_strtab_resize_check);
+
/* Prevent recursive resizing. */
- if (DUK_UNLIKELY(heap->st_resizing)) {
+ if (DUK_UNLIKELY(heap->st_resizing != 0U)) {
DUK_D(DUK_DPRINT("prevent recursive strtable resize"));
return;
}
@@ -50011,6 +51548,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin
DUK_HSTRING_GET_BYTELEN(h) == blen &&
DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
/* Found existing entry. */
+ DUK_STATS_INC(heap, stats_strtab_intern_hit);
return h;
}
h = h->hdr.h_next;
@@ -50024,12 +51562,14 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin
#if defined(DUK_USE_ROM_STRINGS)
h = duk__strtab_romstring_lookup(heap, str, blen, strhash);
if (h != NULL) {
+ DUK_STATS_INC(heap, stats_strtab_intern_hit);
return h;
}
#endif
/* Not found in string table; insert. */
+ DUK_STATS_INC(heap, stats_strtab_intern_miss);
h = duk__strtable_do_intern(heap, str, blen, strhash);
return h; /* may be NULL */
}
@@ -50043,8 +51583,8 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin
*/
DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) {
- char buf[DUK__STRTAB_U32_MAX_STRLEN];
- char *p;
+ duk_uint8_t buf[DUK__STRTAB_U32_MAX_STRLEN];
+ duk_uint8_t *p;
DUK_ASSERT(heap != NULL);
@@ -50339,6 +51879,7 @@ DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t
/* different memory layout, alloc size, and init */
DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0);
DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0);
+ DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_BOUNDFUNC) == 0);
res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject));
if (DUK_UNLIKELY(res == NULL)) {
@@ -50389,6 +51930,27 @@ DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobje
return res;
}
+DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
+ duk_hboundfunc *res;
+
+ res = (duk_hboundfunc *) DUK_ALLOC(heap, sizeof(duk_hboundfunc));
+ if (!res) {
+ return NULL;
+ }
+ DUK_MEMZERO(res, sizeof(duk_hboundfunc));
+
+ duk__init_object_parts(heap, hobject_flags, &res->obj);
+
+ DUK_TVAL_SET_UNDEFINED(&res->target);
+ DUK_TVAL_SET_UNDEFINED(&res->this_binding);
+
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
+ res->args = NULL;
+#endif
+
+ return res;
+}
+
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hbufobj *res;
@@ -50426,11 +51988,10 @@ DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t
res->heap = NULL;
res->valstack = NULL;
res->valstack_end = NULL;
+ res->valstack_alloc_end = NULL;
res->valstack_bottom = NULL;
res->valstack_top = NULL;
- res->callstack = NULL;
res->callstack_curr = NULL;
- res->catchstack = NULL;
res->resumer = NULL;
res->compile_ctx = NULL,
#if defined(DUK_USE_HEAPPTR16)
@@ -50445,14 +52006,12 @@ DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t
}
}
#endif
- /* when nothing is running, API calls are in non-strict mode */
+ /* When nothing is running, API calls are in non-strict mode. */
DUK_ASSERT(res->strict == 0);
res->heap = heap;
- res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
- res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
- res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;
+ /* XXX: Any reason not to merge duk_hthread_alloc.c here? */
return res;
}
@@ -50487,7 +52046,7 @@ DUK_INTERNAL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject
DUK_ASSERT(res->thread == NULL);
DUK_ASSERT(res->varmap == NULL);
- DUK_ASSERT(res->regbase == 0);
+ DUK_ASSERT(res->regbase_byteoff == 0);
return res;
}
@@ -50504,6 +52063,18 @@ DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject
return res;
}
+
+DUK_INTERNAL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
+ duk_hproxy *res;
+
+ res = (duk_hproxy *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hproxy));
+
+ /* Leave ->target and ->handler uninitialized, as caller will always
+ * explicitly initialize them before any side effects are possible.
+ */
+
+ return res;
+}
/*
* Object enumeration support.
*
@@ -50532,7 +52103,6 @@ DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject
*/
#define DUK__ENUM_START_INDEX 2
-#if 0
/* Current implementation suffices for ES2015 for now because there's no symbol
* sorting, so commented out for now.
*/
@@ -50541,55 +52111,72 @@ DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject
* Helper to sort enumeration keys using a callback for pairwise duk_hstring
* comparisons. The keys are in the enumeration object entry part, starting
* from DUK__ENUM_START_INDEX, and the entry part is dense. Entry part values
- * are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true "2" -> true,
+ * are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true, "2" -> true,
* so it suffices to just switch keys without switching values.
*
+ * ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects:
+ * (1) array indices in ascending order,
+ * (2) non-array-index keys in insertion order, and
+ * (3) symbols in insertion order.
+ * http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys.
+ *
+ * This rule is applied to "own properties" at each inheritance level;
+ * non-duplicate parent keys always follow child keys. For example,
+ * an inherited array index will enumerate -after- a symbol in the
+ * child.
+ *
* Insertion sort is used because (1) it's simple and compact, (2) works
* in-place, (3) minimizes operations if data is already nearly sorted,
* (4) doesn't reorder elements considered equal.
* http://en.wikipedia.org/wiki/Insertion_sort
*/
-typedef duk_bool_t (*duk__sort_compare_fn)(duk_hstring *a, duk_hstring *b, duk_uarridx_t val_b);
+/* Sort key, must hold array indices, "not array index" marker, and one more
+ * higher value for symbols.
+ */
+#if !defined(DUK_USE_SYMBOL_BUILTIN)
+typedef duk_uint32_t duk__sort_key_t;
+#elif defined(DUK_USE_64BIT_OPS)
+typedef duk_uint64_t duk__sort_key_t;
+#else
+typedef duk_double_t duk__sort_key_t;
+#endif
+
+/* Get sort key for a duk_hstring. */
+DUK_LOCAL duk__sort_key_t duk__hstring_sort_key(duk_hstring *x) {
+ duk__sort_key_t val;
+
+ /* For array indices [0,0xfffffffe] use the array index as is.
+ * For strings, use 0xffffffff, the marker 'arridx' already in
+ * duk_hstring. For symbols, any value above 0xffffffff works,
+ * as long as it is the same for all symbols; currently just add
+ * the masked flag field into the arridx temporary.
+ */
+ DUK_ASSERT(x != NULL);
+ DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(x) || DUK_HSTRING_GET_ARRIDX_FAST(x) == DUK_HSTRING_NO_ARRAY_INDEX);
-DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk_uarridx_t val_b) {
- duk_uarridx_t val_a;
+ val = (duk__sort_key_t) DUK_HSTRING_GET_ARRIDX_FAST(x);
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+ val = val + (duk__sort_key_t) (DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) x) & DUK_HSTRING_FLAG_SYMBOL);
+#endif
+
+ return (duk__sort_key_t) val;
+}
+
+/* Insert element 'b' after element 'a'? */
+DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk__sort_key_t val_b) {
+ duk__sort_key_t val_a;
DUK_ASSERT(a != NULL);
DUK_ASSERT(b != NULL);
DUK_UNREF(b); /* Not actually needed now, val_b suffices. */
- /* ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects:
- * (1) array indices in ascending order, (2) non-array-index keys in
- * insertion order, symbols in insertion order:
- * http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys.
- *
- * This rule is applied to "own properties" at each inheritance level;
- * non-duplicate parent keys always follow child keys. For example,
- * an inherited array index will enumerate -after- a symbol in the
- * child.
- */
-
- val_a = DUK_HSTRING_GET_ARRIDX_FAST(a);
+ val_a = duk__hstring_sort_key(a);
- if (val_b < val_a) {
- /* Covers:
- * - Both keys are array indices and a > b: don't insert here.
- * - 'b' is array index, 'a' is not: don't insert here.
- */
+ if (val_a > val_b) {
return 0;
} else {
- /* Covers:
- * val_a < val_b where:
- * - Both keys are array indices and a < b: insert here.
- * - 'a' is array index, 'b' is not: insert here.
- * val_a == val_b where:
- * - Both keys are array indices and a == b: insert here
- * (shouldn't actually happen, can't have non-duplicate
- * identical array index keys).
- * - Neither key is an array index: insert here, keeps key
- * order regardless of the keys themselves.
- */
return 1;
}
}
@@ -50612,7 +52199,7 @@ DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk
for (idx = idx_start + 1; idx < idx_end; idx++) {
duk_hstring *h_curr;
duk_int_fast32_t idx_insert;
- duk_uarridx_t val_curr;
+ duk__sort_key_t val_curr;
h_curr = keys[idx];
DUK_ASSERT(h_curr != NULL);
@@ -50622,16 +52209,12 @@ DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk
* (and optimized for) case.
*/
- val_curr = DUK_HSTRING_GET_ARRIDX_FAST(h_curr); /* Remains same during scanning. */
+ val_curr = duk__hstring_sort_key(h_curr); /* Remains same during scanning. */
for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) {
duk_hstring *h_insert;
h_insert = keys[idx_insert];
DUK_ASSERT(h_insert != NULL);
- /* XXX: fixed callback rather than a callback argument; only
- * one argument used and using a callback argument doesn't
- * cause e.g. gcc to inline the callback.
- */
if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) {
break;
}
@@ -50655,88 +52238,11 @@ DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk
if (idx != idx_insert) {
DUK_MEMMOVE((void *) (keys + idx_insert + 1),
(const void *) (keys + idx_insert),
- (size_t) ((idx - idx_insert) * sizeof(duk_hstring *)));
+ ((size_t) (idx - idx_insert) * sizeof(duk_hstring *)));
keys[idx_insert] = h_curr;
}
}
}
-#endif /* disabled */
-
-/*
- * Helper to sort keys into ES2015 [[OwnPropertyKeys]] enumeration order:
- * array keys in ascending order first, followed by keys in insertion
- * order, followed by symbols in insertion order (not handled here).
- * Insertion sort based.
- *
- * This algorithm nominally sorts array indices, but because the "no array
- * index" marker is higher than any array index, non-array-index keys are
- * sorted after array indices. Non-array-index keys are also considered
- * equal for sorting which means that their order is kept as is, so the end
- * result matches ES2015 [[OwnPropertyKeys]].
- *
- * Insertion sort is used because (1) it's simple and compact, (2) works
- * in-place, (3) minimizes operations if data is already nearly sorted,
- * (4) doesn't reorder elements considered equal.
- * http://en.wikipedia.org/wiki/Insertion_sort
- */
-
-DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk_int_fast32_t idx_start, duk_int_fast32_t idx_end) {
- duk_hstring **keys;
- duk_hstring **p_curr, **p_insert, **p_end;
- duk_hstring *h_curr;
- duk_uarridx_t val_highest, val_curr, val_insert;
-
- DUK_ASSERT(h_obj != NULL);
- DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX);
- DUK_ASSERT(idx_end >= idx_start);
- DUK_UNREF(thr);
-
- if (idx_end <= idx_start + 1) {
- return; /* Zero or one element(s). */
- }
-
- keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
- p_curr = keys + idx_start;
- val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
- for (p_curr++, p_end = keys + idx_end; p_curr < p_end; p_curr++) {
- DUK_ASSERT(*p_curr != NULL);
- val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
-
- if (val_curr >= val_highest) {
- val_highest = val_curr;
- continue;
- }
-
- /* Needs to be inserted; scan backwards, since we optimize
- * for the case where elements are nearly in order.
- */
-
- p_insert = p_curr;
- for (;;) {
- p_insert--; /* Start from p_curr - 1. */
- val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
- if (val_insert < val_curr) {
- p_insert++;
- break;
- }
- if (p_insert == keys + idx_start) {
- break;
- }
- }
-
- /* .-- p_insert .-- p_curr
- * v v
- * | ... | insert | ... | curr
- */
-
- h_curr = *p_curr;
- DUK_MEMMOVE((void *) (p_insert + 1),
- (const void *) p_insert,
- (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
- *p_insert = h_curr;
- /* keep val_highest */
- }
-}
/*
* Create an internal enumerator object E, which has its keys ordered
@@ -50747,21 +52253,20 @@ DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk
* scan would be needed to eliminate duplicates found in the prototype chain.
*/
-DUK_LOCAL void duk__add_enum_key(duk_context *ctx, duk_hstring *k) {
+DUK_LOCAL void duk__add_enum_key(duk_hthread *thr, duk_hstring *k) {
/* 'k' may be unreachable on entry so must push without any
* potential for GC.
*/
- duk_push_hstring(ctx, k);
- duk_push_true(ctx);
- duk_put_prop(ctx, -3);
+ duk_push_hstring(thr, k);
+ duk_push_true(thr);
+ duk_put_prop(thr, -3);
}
-DUK_LOCAL void duk__add_enum_key_stridx(duk_context *ctx, duk_small_uint_t stridx) {
- duk__add_enum_key(ctx, DUK_HTHREAD_GET_STRING((duk_hthread *) ctx, stridx));
+DUK_LOCAL void duk__add_enum_key_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
+ duk__add_enum_key(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
}
-DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags) {
duk_hobject *enum_target;
duk_hobject *curr;
duk_hobject *res;
@@ -50773,13 +52278,13 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
duk_uint_fast32_t sort_start_index;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(thr != NULL);
- enum_target = duk_require_hobject(ctx, -1);
+ enum_target = duk_require_hobject(thr, -1);
DUK_ASSERT(enum_target != NULL);
- duk_push_bare_object(ctx);
- res = duk_known_hobject(ctx, -1);
+ duk_push_bare_object(thr);
+ res = duk_known_hobject(thr, -1);
/* [enum_target res] */
@@ -50788,12 +52293,12 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
* enumeration result comes from a proxy trap as there is no
* real object to check against.
*/
- duk_push_hobject(ctx, enum_target);
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_TARGET);
+ duk_push_hobject(thr, enum_target);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_TARGET);
/* Initialize index so that we skip internal control keys. */
- duk_push_int(ctx, DUK__ENUM_START_INDEX);
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_NEXT);
+ duk_push_int(thr, DUK__ENUM_START_INDEX);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
/*
* Proxy object handling
@@ -50803,8 +52308,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
goto skip_proxy;
}
- if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
- enum_target,
+ if (DUK_LIKELY(!duk_hobject_proxy_check(enum_target,
&h_proxy_target,
&h_proxy_handler))) {
goto skip_proxy;
@@ -50816,8 +52320,8 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
* has been obsoleted and "ownKeys" is used instead.
*/
DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
- duk_push_hobject(ctx, h_proxy_handler);
- if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
+ duk_push_hobject(thr, h_proxy_handler);
+ if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
/* No need to replace the 'enum_target' value in stack, only the
* enum_target reference. This also ensures that the original
* enum target is reachable, which keeps the proxy and the proxy
@@ -50827,38 +52331,38 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
enum_target = h_proxy_target;
- duk_push_hobject(ctx, enum_target); /* -> [ ... enum_target res handler undefined target ] */
- duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_INT_TARGET);
+ duk_push_hobject(thr, enum_target); /* -> [ ... enum_target res handler undefined target ] */
+ duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_INT_TARGET);
- duk_pop_2(ctx); /* -> [ ... enum_target res ] */
+ duk_pop_2(thr); /* -> [ ... enum_target res ] */
goto skip_proxy;
}
/* [ ... enum_target res handler trap ] */
- duk_insert(ctx, -2);
- duk_push_hobject(ctx, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
- duk_call_method(ctx, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
- h_trap_result = duk_require_hobject(ctx, -1);
+ duk_insert(thr, -2);
+ duk_push_hobject(thr, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
+ duk_call_method(thr, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
+ h_trap_result = duk_require_hobject(thr, -1);
DUK_UNREF(h_trap_result);
- duk_proxy_ownkeys_postprocess(ctx, h_proxy_target, enum_flags);
+ duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
/* -> [ ... enum_target res trap_result keys_array ] */
/* Copy cleaned up trap result keys into the enumerator object. */
/* XXX: result is a dense array; could make use of that. */
- DUK_ASSERT(duk_is_array(ctx, -1));
- len = (duk_uint_fast32_t) duk_get_length(ctx, -1);
+ DUK_ASSERT(duk_is_array(thr, -1));
+ len = (duk_uint_fast32_t) duk_get_length(thr, -1);
for (i = 0; i < len; i++) {
- (void) duk_get_prop_index(ctx, -1, i);
- DUK_ASSERT(duk_is_string(ctx, -1)); /* postprocess cleaned up */
+ (void) duk_get_prop_index(thr, -1, (duk_uarridx_t) i);
+ DUK_ASSERT(duk_is_string(thr, -1)); /* postprocess cleaned up */
/* [ ... enum_target res trap_result keys_array val ] */
- duk_push_true(ctx);
+ duk_push_true(thr);
/* [ ... enum_target res trap_result keys_array val true ] */
- duk_put_prop(ctx, -5);
+ duk_put_prop(thr, -5);
}
/* [ ... enum_target res trap_result keys_array ] */
- duk_pop_2(ctx);
- duk_remove_m2(ctx);
+ duk_pop_2(thr);
+ duk_remove_m2(thr);
/* [ ... res ] */
@@ -50951,10 +52455,10 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
/* This is a bit fragile: the string is not
* reachable until it is pushed by the helper.
*/
- k = duk_heap_strtable_intern_u32_checked(thr, i);
+ k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i);
DUK_ASSERT(k);
- duk__add_enum_key(ctx, k);
+ duk__add_enum_key(thr, k);
/* [enum_target res] */
}
@@ -50965,11 +52469,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
*/
if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
- duk__add_enum_key_stridx(ctx, DUK_STRIDX_LENGTH);
- }
- } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(curr)) {
- if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
- duk__add_enum_key_stridx(ctx, DUK_STRIDX_LENGTH);
+ duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
}
}
@@ -50985,10 +52485,10 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (DUK_TVAL_IS_UNUSED(tv)) {
continue;
}
- k = duk_heap_strtable_intern_u32_checked(thr, i); /* Fragile reachability. */
+ k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); /* Fragile reachability. */
DUK_ASSERT(k);
- duk__add_enum_key(ctx, k);
+ duk__add_enum_key(thr, k);
/* [enum_target res] */
}
@@ -50996,7 +52496,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) {
/* Array .length comes after numeric indices. */
if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
- duk__add_enum_key_stridx(ctx, DUK_STRIDX_LENGTH);
+ duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
}
}
@@ -51023,6 +52523,9 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
continue;
}
+#if !defined(DUK_USE_PREFER_SIZE)
+ need_sort = 1;
+#endif
} else {
DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k)); /* would also have symbol flag */
if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) {
@@ -51046,7 +52549,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
- duk__add_enum_key(ctx, k);
+ duk__add_enum_key(thr, k);
/* [enum_target res] */
}
@@ -51069,11 +52572,11 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) {
#if defined(DUK_USE_PREFER_SIZE)
- duk__sort_enum_keys_es6(thr, res, sort_start_index, sort_end_index);
+ duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
#else
if (need_sort) {
DUK_DDD(DUK_DDDPRINT("need to sort"));
- duk__sort_enum_keys_es6(thr, res, sort_start_index, sort_end_index);
+ duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
} else {
DUK_DDD(DUK_DDDPRINT("no need to sort"));
}
@@ -51091,7 +52594,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
/* [enum_target res] */
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
/* [res] */
@@ -51106,7 +52609,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
/* Sort to ES2015 order which works for pure array incides but
* also for mixed keys.
*/
- duk__sort_enum_keys_es6(thr, res, DUK__ENUM_START_INDEX, DUK_HOBJECT_GET_ENEXT(res));
+ duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) DUK__ENUM_START_INDEX, (duk_int_fast32_t) DUK_HOBJECT_GET_ENEXT(res));
}
#if defined(DUK_USE_ES6_PROXY)
@@ -51115,7 +52618,7 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
/* compact; no need to seal because object is internal */
duk_hobject_compact_props(thr, res);
- DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
}
/*
@@ -51126,24 +52629,23 @@ DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint
*
* Returns zero without pushing anything on the stack otherwise.
*/
-DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value) {
duk_hobject *e;
duk_hobject *enum_target;
duk_hstring *res = NULL;
duk_uint_fast32_t idx;
duk_bool_t check_existence;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(thr != NULL);
/* [... enum] */
- e = duk_require_hobject(ctx, -1);
+ e = duk_require_hobject(thr, -1);
/* XXX use get tval ptr, more efficient */
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_NEXT);
- idx = (duk_uint_fast32_t) duk_require_uint(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_NEXT);
+ idx = (duk_uint_fast32_t) duk_require_uint(thr, -1);
+ duk_pop(thr);
DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
/* Enumeration keys are checked against the enumeration target (to see
@@ -51151,18 +52653,18 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t
* be the proxy, and checking key existence against the proxy is not
* required (or sensible, as the keys may be fully virtual).
*/
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET);
- enum_target = duk_require_hobject(ctx, -1);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TARGET);
+ enum_target = duk_require_hobject(thr, -1);
DUK_ASSERT(enum_target != NULL);
#if defined(DUK_USE_ES6_PROXY)
- check_existence = (!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(enum_target));
+ check_existence = (!DUK_HOBJECT_IS_PROXY(enum_target));
#else
check_existence = 1;
#endif
- duk_pop(ctx); /* still reachable */
+ duk_pop(thr); /* still reachable */
DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
- (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(thr, -1)));
/* no array part */
for (;;) {
@@ -51194,25 +52696,25 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t
DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
- duk_push_u32(ctx, (duk_uint32_t) idx);
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_NEXT);
+ duk_push_u32(thr, (duk_uint32_t) idx);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
/* [... enum] */
if (res) {
- duk_push_hstring(ctx, res);
+ duk_push_hstring(thr, res);
if (get_value) {
- duk_push_hobject(ctx, enum_target);
- duk_dup_m2(ctx); /* -> [... enum key enum_target key] */
- duk_get_prop(ctx, -2); /* -> [... enum key enum_target val] */
- duk_remove_m2(ctx); /* -> [... enum key val] */
- duk_remove(ctx, -3); /* -> [... key val] */
+ duk_push_hobject(thr, enum_target);
+ duk_dup_m2(thr); /* -> [... enum key enum_target key] */
+ duk_get_prop(thr, -2); /* -> [... enum key enum_target val] */
+ duk_remove_m2(thr); /* -> [... enum key val] */
+ duk_remove(thr, -3); /* -> [... key val] */
} else {
- duk_remove_m2(ctx); /* -> [... key] */
+ duk_remove_m2(thr); /* -> [... key] */
}
return 1;
} else {
- duk_pop(ctx); /* -> [...] */
+ duk_pop(thr); /* -> [...] */
return 0;
}
}
@@ -51222,25 +52724,22 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t
* described in E5 Section 15.2.3.14.
*/
-DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags) {
duk_hobject *e;
- duk_harray *a;
duk_hstring **keys;
duk_tval *tv;
duk_uint_fast32_t count;
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL);
- DUK_UNREF(thr);
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(duk_get_hobject(thr, -1) != NULL);
/* Create a temporary enumerator to get the (non-duplicated) key list;
* the enumerator state is initialized without being needed, but that
* has little impact.
*/
- duk_hobject_enumerator_create(ctx, enum_flags);
- e = duk_known_hobject(ctx, -1);
+ duk_hobject_enumerator_create(thr, enum_flags);
+ e = duk_known_hobject(thr, -1);
/* [enum_target enum res] */
@@ -51248,11 +52747,9 @@ DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_sma
DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX);
count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX);
- a = duk_push_harray_with_size(ctx, count);
- DUK_ASSERT(a != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ASIZE((duk_hobject *) a) == count);
- DUK_ASSERT(a->length == count);
- tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
+ /* XXX: uninit would be OK */
+ tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count);
+ DUK_ASSERT(count == 0 || tv != NULL);
/* Fill result array, no side effects. */
@@ -51271,7 +52768,7 @@ DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_sma
}
/* [enum_target enum res] */
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
/* [enum_target res] */
@@ -51347,7 +52844,6 @@ DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject
/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
- duk_context *ctx = (duk_context *) thr;
duk_hbuffer_dynamic *h_buf;
duk_bitencoder_ctx be_ctx_alloc;
duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
@@ -51361,15 +52857,11 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr
DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
- /* XXX: add proper spare handling to dynamic buffer, to minimize
- * reallocs; currently there is no spare at all.
- */
-
num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
- duk_push_dynamic_buffer(ctx, (duk_size_t) curr_offset);
- h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, -1);
+ duk_push_dynamic_buffer(thr, (duk_size_t) curr_offset);
+ h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
@@ -51421,17 +52913,17 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr
duk_be_encode(be_ctx, 0, 1);
} else if (diff_line >= 1 && diff_line <= 4) {
/* 1 0 <2 bits> */
- duk_be_encode(be_ctx, (0x02 << 2) + (diff_line - 1), 4);
+ duk_be_encode(be_ctx, (duk_uint32_t) ((0x02 << 2) + (diff_line - 1)), 4);
} else if (diff_line >= -0x80 && diff_line <= 0x7f) {
/* 1 1 0 <8 bits> */
DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
- duk_be_encode(be_ctx, (0x06 << 8) + (diff_line + 0x80), 11);
+ duk_be_encode(be_ctx, (duk_uint32_t) ((0x06 << 8) + (diff_line + 0x80)), 11);
} else {
/* 1 1 1 <32 bits>
* Encode in two parts to avoid bitencode 24-bit limitation
*/
- duk_be_encode(be_ctx, (0x07 << 16) + ((next_line >> 16) & 0xffffU), 19);
- duk_be_encode(be_ctx, next_line & 0xffffU, 16);
+ duk_be_encode(be_ctx, (duk_uint32_t) ((0x07 << 16) + ((next_line >> 16) & 0xffff)), 19);
+ duk_be_encode(be_ctx, (duk_uint32_t) (next_line & 0xffff), 16);
}
curr_line = next_line;
@@ -51448,11 +52940,11 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr
new_size = (duk_size_t) curr_offset;
duk_hbuffer_resize(thr, h_buf, new_size);
- (void) duk_to_fixed_buffer(ctx, -1, NULL);
+ (void) duk_to_fixed_buffer(thr, -1, NULL);
DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
(long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
}
/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
@@ -51557,7 +53049,7 @@ DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk
return 0;
}
-DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc) {
+DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc) {
duk_hbuffer_fixed *pc2line;
duk_uint_fast32_t line;
@@ -51567,15 +53059,15 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_i
* future work in debugger.rst).
*/
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_PC2LINE);
- pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
+ duk_get_prop_stridx(thr, idx_func, DUK_STRIDX_INT_PC2LINE);
+ pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(thr, -1);
if (pc2line != NULL) {
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
- line = duk__hobject_pc2line_query_raw((duk_hthread *) ctx, pc2line, (duk_uint_fast32_t) pc);
+ line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc);
} else {
line = 0;
}
- duk_pop(ctx);
+ duk_pop(thr);
return line;
}
@@ -51631,17 +53123,17 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_i
#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX
-/* marker values for hash part */
+/* Marker values for hash part. */
#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED
#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
-/* valstack space that suffices for all local calls, including recursion
- * of other than Duktape calls (getters etc)
+/* Valstack space that suffices for all local calls, excluding any recursion
+ * into Ecmascript or Duktape/C calls (Proxy, getters, etc).
*/
#define DUK__VALSTACK_SPACE 10
-/* valstack space allocated especially for proxy lookup which does a
- * recursive property lookup
+/* Valstack space allocated especially for proxy lookup which does a
+ * recursive property lookup.
*/
#define DUK__VALSTACK_PROXY_LOOKUP 20
@@ -51700,7 +53192,7 @@ DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
t = DUK_TVAL_GET_FASTINT(tv);
- if ((t & ~0xffffffffULL) != 0) {
+ if (((duk_uint64_t) t & ~DUK_U64_CONSTANT(0xffffffff)) != 0) {
/* Catches >0x100000000 and negative values. */
return DUK__NO_ARRAY_INDEX;
}
@@ -51719,14 +53211,14 @@ DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
* Also check if it's a valid array index and return that (or DUK__NO_ARRAY_INDEX
* if not).
*/
-DUK_LOCAL duk_uint32_t duk__to_property_key(duk_context *ctx, duk_idx_t idx, duk_hstring **out_h) {
+DUK_LOCAL duk_uint32_t duk__to_property_key(duk_hthread *thr, duk_idx_t idx, duk_hstring **out_h) {
duk_uint32_t arr_idx;
duk_hstring *h;
duk_tval *tv_dst;
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(thr != NULL);
DUK_ASSERT(out_h != NULL);
- DUK_ASSERT(duk_is_valid_index(ctx, idx));
+ DUK_ASSERT(duk_is_valid_index(thr, idx));
DUK_ASSERT(idx < 0);
/* XXX: The revised ES2015 ToPropertyKey() handling (ES5.1 was just
@@ -51735,7 +53227,7 @@ DUK_LOCAL duk_uint32_t duk__to_property_key(duk_context *ctx, duk_idx_t idx, duk
* but still be compliant and share code.
*/
- tv_dst = DUK_GET_TVAL_NEGIDX((duk_hthread *) ctx, idx); /* intentionally unvalidated */
+ tv_dst = DUK_GET_TVAL_NEGIDX(thr, idx); /* intentionally unvalidated */
if (DUK_TVAL_IS_STRING(tv_dst)) {
/* Most important path: strings and plain symbols are used as
* is. For symbols the array index check below is unnecessary
@@ -51745,7 +53237,7 @@ DUK_LOCAL duk_uint32_t duk__to_property_key(duk_context *ctx, duk_idx_t idx, duk
*/
h = DUK_TVAL_GET_STRING(tv_dst);
} else {
- h = duk_to_property_key_hstring(ctx, idx);
+ h = duk_to_property_key_hstring(thr, idx);
}
DUK_ASSERT(h != NULL);
*out_h = h;
@@ -51754,16 +53246,9 @@ DUK_LOCAL duk_uint32_t duk__to_property_key(duk_context *ctx, duk_idx_t idx, duk
return arr_idx;
}
-DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_context *ctx, duk_tval *tv_key, duk_hstring **out_h) {
- duk_push_tval(ctx, tv_key); /* XXX: could use an unsafe push here */
- return duk__to_property_key(ctx, -1, out_h);
-}
-
-/* String is an own (virtual) property of a lightfunc. */
-DUK_LOCAL duk_bool_t duk__key_is_lightfunc_ownprop(duk_hthread *thr, duk_hstring *key) {
- DUK_UNREF(thr);
- return (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_NAME(thr));
+DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_hthread *thr, duk_tval *tv_key, duk_hstring **out_h) {
+ duk_push_tval(thr, tv_key); /* XXX: could use an unsafe push here */
+ return duk__to_property_key(thr, -1, out_h);
}
/* String is an own (virtual) property of a plain buffer. */
@@ -51890,8 +53375,8 @@ DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint
* for out_min_size as intended.
*/
- *out_used = used;
- *out_min_size = highest_idx + 1; /* 0 if no used entries */
+ *out_used = (duk_uint32_t) used;
+ *out_min_size = (duk_uint32_t) (highest_idx + 1); /* 0 if no used entries */
}
/* Check array density and indicate whether or not the array part should be abandoned. */
@@ -51946,13 +53431,9 @@ DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx
*/
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
- duk_tval *tv_target;
- duk_tval *tv_handler;
- duk_hobject *h_target;
- duk_hobject *h_handler;
+DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
+ duk_hproxy *h_proxy;
- DUK_ASSERT(thr != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(out_target != NULL);
DUK_ASSERT(out_handler != NULL);
@@ -51960,31 +53441,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *o
/* Caller doesn't need to check exotic proxy behavior (but does so for
* some fast paths).
*/
- if (DUK_LIKELY(!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ if (DUK_LIKELY(!DUK_HOBJECT_IS_PROXY(obj))) {
return 0;
}
+ h_proxy = (duk_hproxy *) obj;
+ DUK_ASSERT_HPROXY_VALID(h_proxy);
- tv_handler = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_HANDLER(thr));
- if (!tv_handler) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_handler));
- h_handler = DUK_TVAL_GET_OBJECT(tv_handler);
- DUK_ASSERT(h_handler != NULL);
- *out_handler = h_handler;
- tv_handler = NULL; /* avoid issues with relocation */
-
- tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_TARGET(thr));
- if (!tv_target) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
- h_target = DUK_TVAL_GET_OBJECT(tv_target);
- DUK_ASSERT(h_target != NULL);
- *out_target = h_target;
- tv_target = NULL; /* avoid issues with relocation */
+ DUK_ASSERT(h_proxy->handler != NULL);
+ DUK_ASSERT(h_proxy->target != NULL);
+ *out_handler = h_proxy->handler;
+ *out_target = h_proxy->target;
return 1;
}
@@ -51994,25 +53460,21 @@ DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *o
* If a Proxy is revoked, an error is thrown.
*/
#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj) {
- duk_hobject *h_target;
- duk_hobject *h_handler;
-
- DUK_ASSERT(thr != NULL);
+DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj) {
DUK_ASSERT(obj != NULL);
/* Resolve Proxy targets until Proxy chain ends. No explicit check for
- * a Proxy loop: user code cannot create such a loop without tweaking
- * internal properties directly.
+ * a Proxy loop: user code cannot create such a loop (it would only be
+ * possible by editing duk_hproxy references directly).
*/
- while (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
- if (duk_hobject_proxy_check(thr, obj, &h_target, &h_handler)) {
- DUK_ASSERT(h_target != NULL);
- obj = h_target;
- } else {
- break;
- }
+ while (DUK_HOBJECT_IS_PROXY(obj)) {
+ duk_hproxy *h_proxy;
+
+ h_proxy = (duk_hproxy *) obj;
+ DUK_ASSERT_HPROXY_VALID(h_proxy);
+ obj = h_proxy->target;
+ DUK_ASSERT(obj != NULL);
}
DUK_ASSERT(obj != NULL);
@@ -52022,7 +53484,6 @@ DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk
#if defined(DUK_USE_ES6_PROXY)
DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, duk_small_uint_t stridx_trap, duk_tval *tv_key, duk_hobject **out_target) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *h_handler;
DUK_ASSERT(thr != NULL);
@@ -52030,7 +53491,7 @@ DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, d
DUK_ASSERT(tv_key != NULL);
DUK_ASSERT(out_target != NULL);
- if (!duk_hobject_proxy_check(thr, obj, out_target, &h_handler)) {
+ if (!duk_hobject_proxy_check(obj, out_target, &h_handler)) {
return 0;
}
DUK_ASSERT(*out_target != NULL);
@@ -52072,16 +53533,16 @@ DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, d
/* XXX: C recursion limit if proxies are allowed as handler/target values */
- duk_require_stack(ctx, DUK__VALSTACK_PROXY_LOOKUP);
- duk_push_hobject(ctx, h_handler);
- if (duk_get_prop_stridx_short(ctx, -1, stridx_trap)) {
+ duk_require_stack(thr, DUK__VALSTACK_PROXY_LOOKUP);
+ duk_push_hobject(thr, h_handler);
+ if (duk_get_prop_stridx_short(thr, -1, stridx_trap)) {
/* -> [ ... handler trap ] */
- duk_insert(ctx, -2); /* -> [ ... trap handler ] */
+ duk_insert(thr, -2); /* -> [ ... trap handler ] */
/* stack prepped for func call: [ ... trap handler ] */
return 1;
} else {
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
return 0;
}
}
@@ -52122,7 +53583,6 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
duk_uint32_t new_a_size,
duk_uint32_t new_h_size,
duk_bool_t abandon_array) {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_t prev_ms_base_flags;
duk_uint32_t new_alloc_size;
duk_uint32_t new_e_size_adjusted;
@@ -52140,7 +53600,6 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */
DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
@@ -52150,6 +53609,8 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_object_realloc_props);
+
/*
* Pre resize assertions.
*/
@@ -52174,7 +53635,8 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
new_e_size_adjusted = new_e_size;
#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
- new_e_size_adjusted = (new_e_size + DUK_HOBJECT_ALIGN_TARGET - 1) & (~(DUK_HOBJECT_ALIGN_TARGET - 1));
+ new_e_size_adjusted = (new_e_size + (duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U) &
+ (~((duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U));
DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
(long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
DUK_ASSERT(new_e_size_adjusted >= new_e_size);
@@ -52251,6 +53713,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
*/
#if 0 /* XXX: inject test */
if (1) {
+ new_p = NULL;
goto alloc_failed;
}
#endif
@@ -52305,6 +53768,8 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
*/
DUK_ASSERT(new_a_size == 0);
+ DUK_STATS_INC(thr->heap, stats_object_abandon_array);
+
for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
duk_tval *tv1;
duk_tval *tv2;
@@ -52338,15 +53803,15 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
/* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which
* is generous.
*/
- if (!duk_check_stack(ctx, 1)) {
+ if (!duk_check_stack(thr, 1)) {
goto abandon_error;
}
DUK_ASSERT_VALSTACK_SPACE(thr, 1);
- key = duk_heap_strtable_intern_u32(thr->heap, i);
+ key = duk_heap_strtable_intern_u32(thr->heap, (duk_uint32_t) i);
if (key == NULL) {
goto abandon_error;
}
- duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */
+ duk_push_hstring(thr, key); /* keep key reachable for GC etc; guaranteed not to fail */
/* Key is now reachable in the valstack, don't INCREF
* the new allocation yet (we'll steal the refcounts
@@ -52368,7 +53833,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
/* Steal refcounts from value stack. */
DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
- duk_pop_n_nodecref_unsafe(ctx, new_e_next);
+ duk_pop_n_nodecref_unsafe(thr, (duk_idx_t) new_e_next);
}
/*
@@ -52451,7 +53916,6 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
DUK_ASSERT(new_h != NULL);
/* fill new_h with u32 0xff = UNUSED */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
DUK_ASSERT(new_h_size > 0);
DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
@@ -52470,7 +53934,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */
if (new_h[j] == DUK__HASH_UNUSED) {
DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
- new_h[j] = i;
+ new_h[j] = (duk_uint32_t) i;
break;
}
DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
@@ -52510,7 +53974,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
* All done, switch properties ('p') allocation to new one.
*/
- DUK_FREE(thr->heap, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
+ DUK_FREE_CHECKED(thr, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
@@ -52553,7 +54017,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
alloc_failed:
DUK_D(DUK_DPRINT("object property table resize failed"));
- DUK_FREE(thr->heap, new_p); /* OK for NULL. */
+ DUK_FREE_CHECKED(thr, new_p); /* OK for NULL. */
thr->heap->pf_prevent_count--;
thr->heap->ms_base_flags = prev_ms_base_flags;
@@ -52569,6 +54033,55 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
* Helpers to resize properties allocation on specific needs.
*/
+DUK_INTERNAL void duk_hobject_resize_entrypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_e_size) {
+ duk_uint32_t old_e_size;
+ duk_uint32_t new_a_size;
+ duk_uint32_t new_h_size;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(obj != NULL);
+
+ old_e_size = DUK_HOBJECT_GET_ESIZE(obj);
+ if (old_e_size > new_e_size) {
+ new_e_size = old_e_size;
+ }
+#if defined(DUK_USE_HOBJECT_HASH_PART)
+ new_h_size = duk__get_default_h_size(new_e_size);
+#else
+ new_h_size = 0;
+#endif
+ new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
+
+ duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
+}
+
+#if 0 /*unused */
+DUK_INTERNAL void duk_hobject_resize_arraypart(duk_hthread *thr,
+ duk_hobject *obj,
+ duk_uint32_t new_a_size) {
+ duk_uint32_t old_a_size;
+ duk_uint32_t new_e_size;
+ duk_uint32_t new_h_size;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(obj != NULL);
+
+ if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
+ return;
+ }
+ old_a_size = DUK_HOBJECT_GET_ASIZE(obj);
+ if (old_a_size > new_a_size) {
+ new_a_size = old_a_size;
+ }
+ new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
+ new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
+
+ duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
+}
+#endif
+
/* Grow entry part allocation for one additional entry. */
DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
duk_uint32_t old_e_used; /* actually used, non-NULL entries */
@@ -52737,7 +54250,7 @@ DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj)
* but there is no hash part, h_idx is set to -1.
*/
-DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
+DUK_INTERNAL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
DUK_ASSERT(obj != NULL);
DUK_ASSERT(key != NULL);
DUK_ASSERT(e_idx != NULL);
@@ -52760,9 +54273,9 @@ DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *o
n = DUK_HOBJECT_GET_ENEXT(obj);
for (i = 0; i < n; i++) {
if (h_keys_base[i] == key) {
- *e_idx = i;
+ *e_idx = (duk_int_t) i;
*h_idx = -1;
- return;
+ return 1;
}
}
}
@@ -52802,9 +54315,9 @@ DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *o
if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
(long) i, (long) t, (void *) key));
- *e_idx = t;
- *h_idx = i;
- return;
+ *e_idx = (duk_int_t) t;
+ *h_idx = (duk_int_t) i;
+ return 1;
}
DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
(long) i, (long) t));
@@ -52816,9 +54329,8 @@ DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *o
}
#endif /* DUK_USE_HOBJECT_HASH_PART */
- /* not found */
- *e_idx = -1;
- *h_idx = -1;
+ /* Not found, leave e_idx and h_idx unset. */
+ return 0;
}
/* For internal use: get non-accessor entry value */
@@ -52830,16 +54342,17 @@ DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap,
DUK_ASSERT(key != NULL);
DUK_UNREF(heap);
- duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
- if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
- return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
- } else {
- return NULL;
+ if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
+ if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
+ return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
+ }
}
+ return NULL;
}
/* For internal use: get non-accessor entry value and attributes */
-DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs) {
+DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs) {
duk_int_t e_idx;
duk_int_t h_idx;
@@ -52848,14 +54361,15 @@ DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_he
DUK_ASSERT(out_attrs != NULL);
DUK_UNREF(heap);
- duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
- if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
- *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
- return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
- } else {
- *out_attrs = 0;
- return NULL;
+ if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
+ if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
+ *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
+ return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
+ }
}
+ /* If not found, out_attrs is left unset. */
+ return NULL;
}
/* For internal use: get array part value */
@@ -52884,7 +54398,7 @@ DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *
* the entry value refcount. A decref for the previous value is not necessary.
*/
-DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
+DUK_LOCAL duk_int_t duk__hobject_alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
duk_uint32_t idx;
DUK_ASSERT(thr != NULL);
@@ -52928,7 +54442,7 @@ DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj
for (;;) {
duk_uint32_t t = h_base[i];
if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
- DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() inserted key into hash part, %ld -> %ld",
+ DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() inserted key into hash part, %ld -> %ld",
(long) i, (long) idx));
DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
@@ -52937,7 +54451,7 @@ DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj
h_base[i] = idx;
break;
}
- DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i));
+ DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() miss %ld", (long) i));
i = (i + step) & mask;
/* Guaranteed to finish (hash is larger than #props). */
@@ -52952,7 +54466,7 @@ DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj
DUK_ASSERT_DISABLE(idx >= 0);
DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
- return idx;
+ return (duk_int_t) idx;
}
/*
@@ -52970,9 +54484,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobje
DUK_ASSERT(obj != NULL);
DUK_ASSERT(tv_out != NULL);
- /* always in entry part, no need to look up parents etc */
- duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx);
- if (e_idx >= 0) {
+ /* Always in entry part, no need to look up parents etc. */
+ if (duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx));
DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx));
return 1;
@@ -53023,7 +54537,6 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
duk_propdesc *temp_desc,
duk_hobject **out_map,
duk_hobject **out_varenv) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
duk_hobject *varenv;
duk_bool_t rc;
@@ -53040,9 +54553,9 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
return 0;
}
- map = duk_require_hobject(ctx, -1);
+ map = duk_require_hobject(thr, -1);
DUK_ASSERT(map != NULL);
- duk_pop(ctx); /* map is reachable through obj */
+ duk_pop_unsafe(thr); /* map is reachable through obj */
if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
@@ -53051,16 +54564,16 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
/* [... varname] */
DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ASSERT(duk_is_string(ctx, -1)); /* guaranteed when building arguments */
+ (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_ASSERT(duk_is_string(thr, -1)); /* guaranteed when building arguments */
/* get varenv for varname (callee's declarative lexical environment) */
rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
DUK_UNREF(rc);
DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */
- varenv = duk_require_hobject(ctx, -1);
+ varenv = duk_require_hobject(thr, -1);
DUK_ASSERT(varenv != NULL);
- duk_pop(ctx); /* varenv remains reachable through 'obj' */
+ duk_pop_unsafe(thr); /* varenv remains reachable through 'obj' */
DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
@@ -53075,7 +54588,6 @@ duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
* Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
*/
DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
duk_hobject *varenv;
duk_hstring *varname;
@@ -53089,9 +54601,9 @@ DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobj
/* [... varname] */
- varname = duk_require_hstring(ctx, -1);
+ varname = duk_require_hstring(thr, -1);
DUK_ASSERT(varname != NULL);
- duk_pop(ctx); /* varname is still reachable */
+ duk_pop_unsafe(thr); /* varname is still reachable */
DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
"key=%!O, varname=%!O",
@@ -53102,7 +54614,7 @@ DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobj
/* [... value this_binding] */
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
/* leave result on stack top */
return 1;
@@ -53113,7 +54625,6 @@ DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobj
* Assumes stack top contains 'put' value (which is NOT popped).
*/
DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
duk_hobject *varenv;
duk_hstring *varname;
@@ -53127,15 +54638,15 @@ DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *o
/* [... put_value varname] */
- varname = duk_require_hstring(ctx, -1);
+ varname = duk_require_hstring(thr, -1);
DUK_ASSERT(varname != NULL);
- duk_pop(ctx); /* varname is still reachable */
+ duk_pop_unsafe(thr); /* varname is still reachable */
DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
"key=%!O, varname=%!O, value=%!T",
(duk_heaphdr *) key,
(duk_heaphdr *) varname,
- (duk_tval *) duk_require_tval(ctx, -1)));
+ (duk_tval *) duk_require_tval(thr, -1)));
/* [... put_value] */
@@ -53147,7 +54658,7 @@ DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *o
* the property write call.
*/
- duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, -1), throw_flag);
+ duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, -1), throw_flag);
/* [... put_value] */
}
@@ -53157,7 +54668,6 @@ DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *o
* variable/argument itself (where the map points) is not deleted.
*/
DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *map;
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
@@ -53167,9 +54677,9 @@ DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject
return;
}
- map = duk_require_hobject(ctx, -1);
+ map = duk_require_hobject(thr, -1);
DUK_ASSERT(map != NULL);
- duk_pop(ctx); /* map is reachable through obj */
+ duk_pop_unsafe(thr); /* map is reachable through obj */
DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
(duk_heaphdr *) key));
@@ -53221,7 +54731,6 @@ DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject
*/
DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv;
DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
@@ -53230,7 +54739,6 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
(long) flags, (long) arr_idx,
(duk_heaphdr *) obj, (duk_heaphdr *) key));
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(obj != NULL);
@@ -53238,51 +54746,39 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
DUK_ASSERT(out_desc != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- /* XXX: optimize this filling behavior later */
+ DUK_STATS_INC(thr->heap, stats_getownpropdesc_count);
+
+ /* Each code path returning 1 (= found) must fill in all the output
+ * descriptor fields. We don't do it beforehand because it'd be
+ * unnecessary work if the property isn't found and would happen
+ * multiple times for an inheritance chain.
+ */
+ DUK_ASSERT_SET_GARBAGE(out_desc, sizeof(*out_desc));
+#if 0
out_desc->flags = 0;
out_desc->get = NULL;
out_desc->set = NULL;
out_desc->e_idx = -1;
out_desc->h_idx = -1;
out_desc->a_idx = -1;
+#endif
/*
- * Array part
- */
-
- if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
- if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
- if (!DUK_TVAL_IS_UNUSED(tv)) {
- DUK_DDD(DUK_DDDPRINT("-> found in array part"));
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_tval(ctx, tv);
- }
- /* implicit attributes */
- out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_CONFIGURABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE;
- out_desc->a_idx = arr_idx;
- goto prop_found;
- }
- }
- /* assume array part is comprehensive (contains all array indexed elements
- * or none of them); hence no need to check the entries part here.
- */
- DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property (has array part, "
- "should be there if present)"));
- goto prop_not_found_concrete;
- }
-
- /*
- * Entries part
+ * Try entries part first because it's the common case.
+ *
+ * Array part lookups are usually handled by the array fast path, and
+ * are not usually inherited. Array and entry parts never contain the
+ * same keys so the entry part vs. array part order doesn't matter.
*/
- duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx);
- if (out_desc->e_idx >= 0) {
+ if (duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx)) {
duk_int_t e_idx = out_desc->e_idx;
+ DUK_ASSERT(out_desc->e_idx >= 0);
+ out_desc->a_idx = -1;
out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
- if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) {
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ if (DUK_UNLIKELY(out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR)) {
DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
@@ -53290,23 +54786,49 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
/* a dummy undefined value is pushed to make valstack
* behavior uniform for caller
*/
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
} else {
DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_tval(ctx, tv);
+ duk_push_tval(thr, tv);
}
}
goto prop_found;
}
/*
- * Not found as a concrete property, check for virtual properties.
+ * Try array part.
*/
- prop_not_found_concrete:
+ if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
+ if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
+ tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
+ if (!DUK_TVAL_IS_UNUSED(tv)) {
+ DUK_DDD(DUK_DDDPRINT("-> found in array part"));
+ if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
+ duk_push_tval(thr, tv);
+ }
+ /* implicit attributes */
+ out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
+ DUK_PROPDESC_FLAG_CONFIGURABLE |
+ DUK_PROPDESC_FLAG_ENUMERABLE;
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = (duk_int_t) arr_idx; /* XXX: limit 2G due to being signed */
+ goto prop_found;
+ }
+ }
+ }
+
+ DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property"));
+
+ /*
+ * Not found as a concrete property, check for virtual properties.
+ */
if (!DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(obj)) {
/* Quick skip. */
@@ -53326,15 +54848,20 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, (duk_uint_t) a->length);
+ duk_push_uint(thr, (duk_uint_t) a->length);
}
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
if (DUK_HARRAY_LENGTH_WRITABLE(a)) {
out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE;
}
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
+ goto prop_found_noexotic; /* cannot be arguments exotic */
}
} else if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
@@ -53352,14 +54879,19 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_hstring(ctx, h_val);
- duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
+ duk_push_hstring(thr, h_val);
+ duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
}
out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
DUK_PROPDESC_FLAG_VIRTUAL;
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
+ goto prop_found_noexotic; /* cannot be arguments exotic */
} else {
/* index is above internal string length -> property is fully normal */
DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
@@ -53372,12 +54904,17 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
DUK_ASSERT(h_val != NULL);
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
+ duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
}
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
+ goto prop_found_noexotic; /* cannot be arguments exotic */
}
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
@@ -53399,16 +54936,16 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
*/
if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
duk_uint8_t *data;
if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufobj_push_validated_read(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
} else {
DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
- duk_push_uint(ctx, 0);
+ duk_push_uint(thr, 0);
}
}
out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
@@ -53419,9 +54956,14 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
*/
out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
}
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
+ goto prop_found_noexotic; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
} else {
/* index is above internal buffer length -> property is fully normal */
DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
@@ -53433,32 +54975,20 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
/* Length in elements: take into account shift, but
* intentionally don't check the underlying buffer here.
*/
- duk_push_uint(ctx, h_bufobj->length >> h_bufobj->shift);
+ duk_push_uint(thr, h_bufobj->length >> h_bufobj->shift);
}
out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
+ out_desc->get = NULL;
+ out_desc->set = NULL;
+ out_desc->e_idx = -1;
+ out_desc->h_idx = -1;
+ out_desc->a_idx = -1;
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
+ goto prop_found_noexotic; /* cannot be arguments exotic */
}
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
- else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj)) {
- DUK_DDD(DUK_DDDPRINT("duktape/c object exotic property get for key: %!O, arr_idx: %ld",
- (duk_heaphdr *) key, (long) arr_idx));
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
-
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_int16_t func_nargs = ((duk_hnatfunc *) obj)->nargs;
- duk_push_int(ctx, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* not enumerable */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
- }
- }
/* Array properties have exotic behavior but they are concrete,
* so no special handling here.
@@ -53469,15 +54999,16 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
*/
/*
- * Not found as concrete or virtual
+ * Not found as concrete or virtual.
*/
prop_not_found:
DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
+ DUK_STATS_INC(thr->heap, stats_getownpropdesc_miss);
return 0;
/*
- * Found
+ * Found.
*
* Arguments object has exotic post-processing, see E5 Section 10.6,
* description of [[GetOwnProperty]] variant for arguments.
@@ -53487,15 +55018,15 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
/* Notes:
- * - only numbered indices are relevant, so arr_idx fast reject is good
+ * - Only numbered indices are relevant, so arr_idx fast reject is good
* (this is valid unless there are more than 4**32-1 arguments).
- * - since variable lookup has no side effects, this can be skipped if
+ * - Since variable lookup has no side effects, this can be skipped if
* DUK_GETDESC_FLAG_PUSH_VALUE is not set.
*/
- if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
- arr_idx != DUK__NO_ARRAY_INDEX &&
- (flags & DUK_GETDESC_FLAG_PUSH_VALUE)) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
+ arr_idx != DUK__NO_ARRAY_INDEX &&
+ (flags & DUK_GETDESC_FLAG_PUSH_VALUE))) {
duk_propdesc temp_desc;
/* Magically bound variable cannot be an accessor. However,
@@ -53513,13 +55044,15 @@ DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *ob
*/
if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
/* [... old_result result] -> [... result] */
- duk_remove_m2(ctx);
+ duk_remove_m2(thr);
}
}
+ prop_found_noexotic:
+ DUK_STATS_INC(thr->heap, stats_getownpropdesc_hit);
return 1;
}
@@ -53564,6 +55097,8 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
DUK_ASSERT(out_desc != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_getpropdesc_count);
+
arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
@@ -53578,6 +55113,7 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
do {
if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
/* stack contains value (if requested), 'out_desc' is set */
+ DUK_STATS_INC(thr->heap, stats_getpropdesc_hit);
return 1;
}
@@ -53597,6 +55133,7 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
* value to determine whether out_desc can be looked up
*/
+ DUK_STATS_INC(thr->heap, stats_getpropdesc_miss);
return 0;
}
@@ -53631,7 +55168,7 @@ DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, d
!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
!DUK_HOBJECT_IS_BUFOBJ(obj) &&
- !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ !DUK_HOBJECT_IS_PROXY(obj))) {
/* Must have array part and no conflicting exotic behaviors.
* Doesn't need to have array special behavior, e.g. Arguments
* object has array part.
@@ -53754,15 +55291,12 @@ DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr,
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
- duk_context *ctx;
duk_uint32_t idx;
duk_hbufobj *h_bufobj;
duk_uint_t byte_off;
duk_small_uint_t elem_size;
duk_uint8_t *data;
- ctx = (duk_context *) thr;
-
if (!DUK_HOBJECT_IS_BUFOBJ(obj)) {
return 0;
}
@@ -53794,14 +55328,14 @@ DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufobj_push_validated_read(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
} else {
DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
- duk_push_uint(ctx, 0);
+ duk_push_uint(thr, 0);
}
return 1;
@@ -53810,15 +55344,12 @@ DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
- duk_context *ctx;
duk_uint32_t idx;
duk_hbufobj *h_bufobj;
duk_uint_t byte_off;
duk_small_uint_t elem_size;
duk_uint8_t *data;
- ctx = (duk_context *) thr;
-
if (!(DUK_HOBJECT_IS_BUFOBJ(obj) &&
DUK_TVAL_IS_NUMBER(tv_val))) {
return 0;
@@ -53853,22 +55384,22 @@ DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
/* Value is required to be a number in the fast path so there
* are no side effects in write coercion.
*/
- duk_push_tval(ctx, tv_val);
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_push_tval(thr, tv_val);
+ DUK_ASSERT(duk_is_number(thr, -1));
if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufobj_validated_write(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
} else {
DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
return 1;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -53878,7 +55409,6 @@ DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
*/
DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
- duk_context *ctx = (duk_context *) thr;
duk_tval tv_obj_copy;
duk_tval tv_key_copy;
duk_hobject *curr = NULL;
@@ -53891,7 +55421,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
(void *) thr, (void *) tv_obj, (void *) tv_key,
(duk_tval *) tv_obj, (duk_tval *) tv_key));
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(tv_obj != NULL);
@@ -53899,6 +55428,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_getprop_all);
+
/*
* Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
* them being invalidated by a valstack resize.
@@ -53926,7 +55457,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(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));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
return 0;
}
@@ -53960,23 +55491,24 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
pop_count = 0;
} else {
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
pop_count = 1;
}
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
- duk_pop_n(ctx, pop_count);
- duk_push_hstring(ctx, h);
- duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
+ duk_pop_n_unsafe(thr, pop_count);
+ duk_push_hstring(thr, h);
+ duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
+ DUK_STATS_INC(thr->heap, stats_getprop_stringidx);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
"after coercion -> return char)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -53984,20 +55516,21 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* This is a pretty awkward control flow, but we need to recheck the
* key coercion here.
*/
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
}
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
+ duk_pop_unsafe(thr); /* [key] -> [] */
+ duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
+ DUK_STATS_INC(thr->heap, stats_getprop_stringlen);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
"return string length)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -54019,11 +55552,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
if (tmp) {
- duk_push_tval(ctx, tmp);
+ duk_push_tval(thr, tmp);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
"fast path)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_STATS_INC(thr->heap, stats_getprop_arrayidx);
return 1;
}
#endif
@@ -54033,32 +55567,34 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* Read value pushed on stack. */
DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufobj "
"fast path)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
+ DUK_STATS_INC(thr->heap, stats_getprop_bufobjidx);
return 1;
}
#endif
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(curr))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(curr))) {
duk_hobject *h_target;
if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
/* -> [ ... trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
- duk_call_method(ctx, 3 /*nargs*/);
+ DUK_STATS_INC(thr->heap, stats_getprop_proxy);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_push_tval(thr, tv_key); /* P */
+ duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */
+ duk_call_method(thr, 3 /*nargs*/);
/* Target object must be checked for a conflicting
* non-configurable property.
*/
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- duk_tval *tv_hook = duk_require_tval(ctx, -3); /* value from hook */
- duk_tval *tv_targ = duk_require_tval(ctx, -1); /* value from target */
+ duk_tval *tv_hook = duk_require_tval(thr, -3); /* value from hook */
+ duk_tval *tv_targ = duk_require_tval(thr, -1); /* value from target */
duk_bool_t datadesc_reject;
duk_bool_t accdesc_reject;
@@ -54081,9 +55617,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
}
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
} else {
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
return 1; /* return value */
}
@@ -54094,18 +55630,19 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
#endif /* DUK_USE_ES6_PROXY */
if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
+ DUK_STATS_INC(thr->heap, stats_getprop_arguments);
if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
"key matches magically bound property -> skip standard "
"Get with replacement value)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/* no need for 'caller' post-check, because 'key' must be an array index */
- duk_remove_m2(ctx); /* [key result] -> [result] */
+ duk_remove_m2(thr); /* [key result] -> [result] */
return 1;
}
@@ -54139,22 +55676,22 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
pop_count = 0;
} else {
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
pop_count = 1;
}
if (arr_idx != DUK__NO_ARRAY_INDEX &&
arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
- duk_pop_n(ctx, pop_count);
- duk_push_uint(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
-
+ duk_pop_n_unsafe(thr, pop_count);
+ duk_push_uint(thr, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
+ DUK_STATS_INC(thr->heap, stats_getprop_bufferidx);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
"after coercion -> return byte as number)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -54162,20 +55699,21 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* This is a pretty awkward control flow, but we need to recheck the
* key coercion here.
*/
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
}
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
+ duk_pop_unsafe(thr); /* [key] -> [] */
+ duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
+ DUK_STATS_INC(thr->heap, stats_getprop_bufferlen);
DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' "
"after coercion -> return buffer length)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -54191,25 +55729,10 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
}
case DUK_TAG_LIGHTFUNC: {
- duk_int_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_obj);
-
- /* Must coerce key: if key is an object, it may coerce to e.g. 'length'. */
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_int_t lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- duk_pop(ctx);
- duk_push_int(ctx, lf_len);
- return 1;
- } else if (key == DUK_HTHREAD_STRING_NAME(thr)) {
- duk_pop(ctx);
- duk_push_lightfunc_name(ctx, tv_obj);
- return 1;
- }
-
+ /* Lightfuncs inherit getter .name and .length from %NativeFunctionPrototype%. */
DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
- curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
- goto lookup; /* avoid double coercion */
+ curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
+ break;
}
#if defined(DUK_USE_FASTINT)
@@ -54227,9 +55750,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* key coercion (unless already coerced above) */
DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
-
/*
* Property lookup
*/
@@ -54249,14 +55771,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* accessor with defined getter */
DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
- duk_pop(ctx); /* [key undefined] -> [key] */
- duk_push_hobject(ctx, desc.get);
- duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
+ duk_pop_unsafe(thr); /* [key undefined] -> [key] */
+ duk_push_hobject(thr, desc.get);
+ duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */
#if defined(DUK_USE_NONSTD_GETTER_KEY_ARGUMENT)
- duk_dup_m3(ctx);
- duk_call_method(ctx, 1); /* [key getter this key] -> [key retval] */
+ duk_dup_m3(thr);
+ duk_call_method(thr, 1); /* [key getter this key] -> [key retval] */
#else
- duk_call_method(ctx, 0); /* [key getter this] -> [key retval] */
+ duk_call_method(thr, 0); /* [key getter this] -> [key retval] */
#endif
} else {
/* [key value] or [key undefined] */
@@ -54267,7 +55789,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* if accessor without getter, return value is undefined */
DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
- duk_is_undefined(ctx, -1));
+ duk_is_undefined(thr, -1));
/* Note: for an accessor without getter, falling through to
* check for "caller" exotic behavior is unnecessary as
@@ -54292,9 +55814,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
* Not found
*/
- duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */
+ duk_to_undefined(thr, -1); /* [key] -> [undefined] (default value) */
- DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(thr, -1)));
return 0;
/*
@@ -54348,7 +55870,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
*/
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(orig));
- h = duk_get_hobject(ctx, -1); /* NULL if not an object */
+ h = duk_get_hobject(thr, -1); /* NULL if not an object */
if (h &&
DUK_HOBJECT_IS_FUNCTION(h) &&
DUK_HOBJECT_HAS_STRICT(h)) {
@@ -54359,9 +55881,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
}
#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
- duk_remove_m2(ctx); /* [key result] -> [result] */
+ duk_remove_m2(thr); /* [key result] -> [result] */
- DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(ctx, -1)));
+ DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
@@ -54373,7 +55895,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
*/
DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
- duk_context *ctx = (duk_context *) thr;
duk_tval tv_key_copy;
duk_hobject *obj;
duk_hstring *key;
@@ -54412,27 +55933,23 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
obj = DUK_TVAL_GET_OBJECT(tv_obj);
DUK_ASSERT(obj != NULL);
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
} else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
if (duk__key_is_plain_buf_ownprop(thr, DUK_TVAL_GET_BUFFER(tv_obj), key, arr_idx)) {
rc = 1;
goto pop_and_return;
}
obj = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
} else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- rc = 1;
- goto pop_and_return;
- }
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
- /* If not found, resume existence check from Function.prototype.
+ /* If not found, resume existence check from %NativeFunctionPrototype%.
* We can just substitute the value in this case; nothing will
* need the original base value (as would be the case with e.g.
* setters/getters.
*/
- obj = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
+ obj = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
} else {
/* Note: unconditional throw */
DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
@@ -54446,7 +55963,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_UNREF(arr_idx);
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
duk_hobject *h_target;
duk_bool_t tmp_bool;
@@ -54458,10 +55975,10 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
/* [ ... key trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_call_method(ctx, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_push_tval(thr, tv_key); /* P */
+ duk_call_method(thr, 2 /*nargs*/);
+ tmp_bool = duk_to_boolean(thr, -1);
if (!tmp_bool) {
/* Target object must be checked for a conflicting
* non-configurable property.
@@ -54484,7 +56001,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
}
}
- duk_pop_2(ctx); /* [ key trap_result ] -> [] */
+ duk_pop_2_unsafe(thr); /* [ key trap_result ] -> [] */
return tmp_bool;
}
@@ -54498,7 +56015,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
/* fall through */
pop_and_return:
- duk_pop(ctx); /* [ key ] -> [] */
+ duk_pop_unsafe(thr); /* [ key ] -> [] */
return rc;
}
@@ -54551,7 +56068,7 @@ DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tv
/* Very common case. */
duk_int64_t fi;
fi = DUK_TVAL_GET_FASTINT(tv);
- if (fi < 0 || fi > 0xffffffffLL) {
+ if (fi < 0 || fi > DUK_I64_CONSTANT(0xffffffff)) {
goto fail_range;
}
return (duk_uint32_t) fi;
@@ -54664,7 +56181,7 @@ duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
return 1;
} else {
/*
- * Entries part is a bit more complex
+ * Entries part is a bit more complex.
*/
/* Stage 1: find highest preventing non-configurable entry (if any).
@@ -54783,7 +56300,6 @@ duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
/* XXX: is valstack top best place for argument? */
DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
duk_harray *a;
duk_uint32_t old_len;
duk_uint32_t new_len;
@@ -54792,10 +56308,9 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
"new val: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
@@ -54805,14 +56320,14 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
a = (duk_harray *) obj;
DUK_ASSERT_HARRAY_VALID(a);
- DUK_ASSERT(duk_is_valid_index(ctx, -1));
+ DUK_ASSERT(duk_is_valid_index(thr, -1));
/*
* Get old and new length
*/
old_len = a->length;
- new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(ctx, -1));
+ new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
/*
@@ -54885,7 +56400,6 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
*/
DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk_tval tv_obj_copy;
duk_tval tv_key_copy;
duk_tval tv_val_copy;
@@ -54907,13 +56421,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_obj != NULL);
DUK_ASSERT(tv_key != NULL);
DUK_ASSERT(tv_val != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
+ DUK_STATS_INC(thr->heap, stats_putprop_all);
+
/*
* Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
* them being invalidated by a valstack resize.
@@ -54943,7 +56458,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(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));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
return 0;
}
@@ -54963,7 +56478,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
*/
DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
@@ -55022,6 +56537,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val) != 0) {
DUK_DDD(DUK_DDDPRINT("array fast path success"));
+ DUK_STATS_INC(thr->heap, stats_putprop_arrayidx);
return 1;
}
#endif
@@ -55029,25 +56545,27 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufobj fast path"));
+ DUK_STATS_INC(thr->heap, stats_putprop_bufobjidx);
return 1;
}
#endif
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(orig))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(orig))) {
duk_hobject *h_target;
duk_bool_t tmp_bool;
if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
/* -> [ ... trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_push_tval(ctx, tv_val); /* V */
- duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
- duk_call_method(ctx, 4 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
- duk_pop(ctx);
+ DUK_STATS_INC(thr->heap, stats_putprop_proxy);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_push_tval(thr, tv_key); /* P */
+ duk_push_tval(thr, tv_val); /* V */
+ duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */
+ duk_call_method(thr, 4 /*nargs*/);
+ tmp_bool = duk_to_boolean(thr, -1);
+ duk_pop_nodecref_unsafe(thr);
if (!tmp_bool) {
goto fail_proxy_rejected;
}
@@ -55055,11 +56573,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
/* Target object must be checked for a conflicting
* non-configurable property.
*/
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- duk_tval *tv_targ = duk_require_tval(ctx, -1);
+ duk_tval *tv_targ = duk_require_tval(thr, -1);
duk_bool_t datadesc_reject;
duk_bool_t accdesc_reject;
@@ -55081,9 +56599,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
}
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
} else {
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
return 1; /* success */
}
@@ -55118,11 +56636,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
pop_count = 0;
} else {
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
pop_count = 1;
}
@@ -55143,13 +56661,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
else
#endif
{
- duk_push_tval(ctx, tv_val);
- data[arr_idx] = (duk_uint8_t) duk_to_uint32(ctx, -1);
+ duk_push_tval(thr, tv_val);
+ data[arr_idx] = (duk_uint8_t) duk_to_uint32(thr, -1);
pop_count++;
}
- duk_pop_n(ctx, pop_count);
+ duk_pop_n_unsafe(thr, pop_count);
DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
+ DUK_STATS_INC(thr->heap, stats_putprop_bufferidx);
return 1;
}
@@ -55157,11 +56676,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
/* This is a pretty awkward control flow, but we need to recheck the
* key coercion here.
*/
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
"coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
+ (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
}
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
@@ -55180,20 +56699,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
}
case DUK_TAG_LIGHTFUNC: {
- /* All lightfunc own properties are non-writable and the lightfunc
- * is considered non-extensible. However, the write may be captured
- * by an inherited setter which means we can't stop the lookup here.
+ /* Lightfuncs have no own properties and are considered non-extensible.
+ * However, the write may be captured by an inherited setter which
+ * means we can't stop the lookup here.
*/
-
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
-
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- goto fail_not_writable;
- }
-
DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
- curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
- goto lookup; /* avoid double coercion */
+ curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
+ break;
}
#if defined(DUK_USE_FASTINT)
@@ -55209,7 +56721,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
}
DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
lookup:
@@ -55247,16 +56759,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (!setter) {
goto fail_no_setter;
}
- duk_push_hobject(ctx, setter);
- duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
- duk_push_tval(ctx, tv_val); /* [key setter this val] */
+ duk_push_hobject(thr, setter);
+ duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */
+ duk_push_tval(thr, tv_val); /* [key setter this val] */
#if defined(DUK_USE_NONSTD_SETTER_KEY_ARGUMENT)
- duk_dup_m4(ctx);
- duk_call_method(ctx, 2); /* [key setter this val key] -> [key retval] */
+ duk_dup_m4(thr);
+ duk_call_method(thr, 2); /* [key setter this val key] -> [key retval] */
#else
- duk_call_method(ctx, 1); /* [key setter this val] -> [key retval] */
+ duk_call_method(thr, 1); /* [key setter this val] -> [key retval] */
#endif
- duk_pop(ctx); /* ignore retval -> [key] */
+ duk_pop_unsafe(thr); /* ignore retval -> [key] */
goto success_no_arguments_exotic;
}
@@ -55318,9 +56830,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
* compatible with what we need.
*/
- duk_push_tval(ctx, tv_val); /* [key val] */
+ duk_push_tval(thr, tv_val); /* [key val] */
rc = duk__handle_put_array_length(thr, orig);
- duk_pop(ctx); /* [key val] -> [key] */
+ duk_pop_unsafe(thr); /* [key val] -> [key] */
if (!rc) {
goto fail_array_length_partial;
}
@@ -55348,23 +56860,23 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */
byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
+ elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
/* Coerce to number before validating pointers etc so that the
* number coercions in duk_hbufobj_validated_write() are
* guaranteed to be side effect free and not invalidate the
* pointer checks we do here.
*/
- duk_push_tval(ctx, tv_val);
- (void) duk_to_number_m1(ctx);
+ duk_push_tval(thr, tv_val);
+ (void) duk_to_number_m1(thr);
if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufobj_validated_write(ctx, h_bufobj, data, elem_size);
+ duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
} else {
DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
goto success_no_arguments_exotic;
}
}
@@ -55648,7 +57160,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
* refcount; may need a props allocation resize but doesn't
* 'recheck' the valstack.
*/
- e_idx = duk__alloc_entry_checked(thr, orig, key);
+ e_idx = duk__hobject_alloc_entry_checked(thr, orig, key);
DUK_ASSERT(e_idx >= 0);
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
@@ -55716,16 +57228,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
* rework to use tv_val directly?
*/
- duk_push_tval(ctx, tv_val);
+ duk_push_tval(thr, tv_val);
(void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
/* fall thru */
success_no_arguments_exotic:
/* shared exit path now */
DUK_DDD(DUK_DDDPRINT("result: success"));
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 1;
#if defined(DUK_USE_ES6_PROXY)
@@ -55745,10 +57257,10 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(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));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_not_extensible:
@@ -55756,7 +57268,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_not_writable:
@@ -55764,7 +57276,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
#if defined(DUK_USE_ROM_OBJECTS)
@@ -55781,7 +57293,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_no_setter:
@@ -55789,7 +57301,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
fail_internal:
@@ -55797,7 +57309,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_INTERNAL(thr);
}
- duk_pop(ctx); /* remove key */
+ duk_pop_unsafe(thr); /* remove key */
return 0;
}
@@ -55965,7 +57477,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
*/
DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk_hstring *key = NULL;
#if defined(DUK_USE_ES6_PROXY)
duk_propdesc desc;
@@ -55978,7 +57489,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
(void *) thr, (void *) tv_obj, (void *) tv_key,
(duk_tval *) tv_obj, (duk_tval *) tv_key));
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(tv_obj != NULL);
@@ -55989,7 +57499,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
/* Storing the entry top is cheaper here to ensure stack is correct at exit,
* as there are several paths out.
*/
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
DUK_TVAL_IS_NULL(tv_obj)) {
@@ -55997,16 +57507,16 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
goto fail_invalid_base_uncond;
}
- duk_push_tval(ctx, tv_obj);
- duk_push_tval(ctx, tv_key);
+ duk_push_tval(thr, tv_obj);
+ duk_push_tval(thr, tv_key);
- tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -2);
+ tv_obj = DUK_GET_TVAL_NEGIDX(thr, -2);
if (DUK_TVAL_IS_OBJECT(tv_obj)) {
duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
DUK_ASSERT(obj != NULL);
#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
duk_hobject *h_target;
duk_bool_t tmp_bool;
@@ -56015,11 +57525,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
/* -> [ ... obj key trap handler ] */
DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_dup_m4(ctx); /* P */
- duk_call_method(ctx, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
- duk_pop(ctx);
+ duk_push_hobject(thr, h_target); /* target */
+ duk_dup_m4(thr); /* P */
+ duk_call_method(thr, 2 /*nargs*/);
+ tmp_bool = duk_to_boolean(thr, -1);
+ duk_pop_nodecref_unsafe(thr);
if (!tmp_bool) {
goto fail_proxy_rejected; /* retval indicates delete failed */
}
@@ -56027,8 +57537,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
/* Target object must be checked for a conflicting
* non-configurable property.
*/
- tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
- arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
+ tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
+ arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
DUK_ASSERT(key != NULL);
if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
@@ -56054,7 +57564,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
}
#endif /* DUK_USE_ES6_PROXY */
- arr_idx = duk__to_property_key(ctx, -1, &key);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
@@ -56070,7 +57580,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
DUK_ASSERT(h != NULL);
- arr_idx = duk__to_property_key(ctx, -1, &key);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
@@ -56089,7 +57599,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
DUK_ASSERT(h != NULL);
- arr_idx = duk__to_property_key(ctx, -1, &key);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
@@ -56101,16 +57611,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
goto fail_not_configurable;
}
} else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
- /* Lightfunc virtual properties are non-configurable, so
- * reject if match any of them.
+ /* Lightfunc has no virtual properties since Duktape 2.2
+ * so success. Still must coerce key for side effects.
*/
- arr_idx = duk__to_property_key(ctx, -1, &key);
+ arr_idx = duk__to_property_key(thr, -1, &key);
DUK_ASSERT(key != NULL);
-
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- goto fail_not_configurable;
- }
+ DUK_UNREF(key);
}
/* non-object base, no offending virtual property */
@@ -56118,17 +57625,17 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
goto done_rc;
done_rc:
- duk_set_top(ctx, entry_top);
+ duk_set_top_unsafe(thr, entry_top);
return rc;
fail_invalid_base_uncond:
/* Note: unconditional throw */
- DUK_ASSERT(duk_get_top(ctx) == entry_top);
+ DUK_ASSERT(duk_get_top(thr) == entry_top);
#if defined(DUK_USE_PARANOID_ERRORS)
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
#else
DUK_ERROR_FMT2(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));
+ duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
return 0;
@@ -56137,7 +57644,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
}
- duk_set_top(ctx, entry_top);
+ duk_set_top_unsafe(thr, entry_top);
return 0;
#endif
@@ -56145,7 +57652,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
}
- duk_set_top(ctx, entry_top);
+ duk_set_top_unsafe(thr, entry_top);
return 0;
}
@@ -56169,7 +57676,6 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
*/
DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk_propdesc desc;
duk_uint32_t arr_idx;
duk_int_t e_idx;
@@ -56179,7 +57685,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
(void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
- (unsigned long) flags, (duk_tval *) duk_get_tval(ctx, -1)));
+ (unsigned long) flags, (duk_tval *) duk_get_tval(thr, -1)));
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
@@ -56187,7 +57693,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
DUK_ASSERT(key != NULL);
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- DUK_ASSERT(duk_is_valid_index(ctx, -1)); /* contains value */
+ DUK_ASSERT(duk_is_valid_index(thr, -1)); /* contains value */
arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
@@ -56229,7 +57735,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
duk_uint32_t prev_len;
prev_len = ((duk_harray *) obj)->length;
#endif
- new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(ctx, -1));
+ new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
((duk_harray *) obj)->length = new_len;
DUK_D(DUK_DPRINT("internal define property for array .length: %ld -> %ld",
(long) prev_len, (long) ((duk_harray *) obj)->length));
@@ -56259,7 +57765,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
}
DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
- e_idx = duk__alloc_entry_checked(thr, obj, key); /* increases key refcount */
+ e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); /* increases key refcount */
DUK_ASSERT(e_idx >= 0);
DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
@@ -56270,7 +57776,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
write_value:
/* tv1 points to value storage */
- tv2 = duk_require_tval(ctx, -1); /* late lookup, avoid side effects */
+ tv2 = duk_require_tval(thr, -1); /* late lookup, avoid side effects */
DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
(duk_tval *) tv1, (duk_tval *) tv2));
@@ -56278,7 +57784,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
goto pop_exit;
pop_exit:
- duk_pop(ctx); /* remove in_val */
+ duk_pop_unsafe(thr); /* remove in_val */
return;
error_virtual: /* share error message */
@@ -56294,14 +57800,13 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
*/
DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk_hstring *key;
duk_tval *tv1, *tv2;
DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
"arr_idx=%ld, flags=0x%02lx, val=%!T",
(void *) thr, obj, (long) arr_idx, (unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
@@ -56322,23 +57827,23 @@ DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr,
DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
- tv2 = duk_require_tval(ctx, -1);
+ tv2 = duk_require_tval(thr, -1);
DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- duk_pop(ctx); /* [ ...val ] -> [ ... ] */
+ duk_pop_unsafe(thr); /* [ ...val ] -> [ ... ] */
return;
}
DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
- key = duk_push_uint_to_hstring(ctx, (duk_uint_t) arr_idx);
+ key = duk_push_uint_to_hstring(thr, (duk_uint_t) arr_idx);
DUK_ASSERT(key != NULL);
- duk_insert(ctx, -2); /* [ ... val key ] -> [ ... key val ] */
+ duk_insert(thr, -2); /* [ ... val key ] -> [ ... key val ] */
duk_hobject_define_property_internal(thr, obj, key, flags);
- duk_pop(ctx); /* [ ... key ] -> [ ... ] */
+ duk_pop_unsafe(thr); /* [ ... key ] -> [ ... ] */
}
/*
@@ -56346,10 +57851,9 @@ DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr,
*/
DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
duk_double_t val;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_ASSERT(obj != NULL);
/* Fast path for Arrays. */
@@ -56358,13 +57862,13 @@ DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *ob
}
/* Slow path, .length can be e.g. accessor, obj can be a Proxy, etc. */
- duk_push_hobject(ctx, obj);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
+ duk_push_hobject(thr, obj);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_LENGTH);
(void) duk_hobject_getprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1));
- val = duk_to_number_m1(ctx);
- duk_pop_3(ctx);
+ DUK_GET_TVAL_NEGIDX(thr, -2),
+ DUK_GET_TVAL_NEGIDX(thr, -1));
+ val = duk_to_number_m1(thr);
+ duk_pop_3_unsafe(thr);
/* This isn't part of Ecmascript semantics; return a value within
* duk_size_t range, or 0 otherwise.
@@ -56416,31 +57920,27 @@ DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) {
* [ ... key ] -> [ ... desc/undefined ]
*/
-DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_context *ctx, duk_idx_t obj_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx) {
duk_hobject *obj;
duk_hstring *key;
duk_propdesc pd;
- duk_bool_t rc;
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- obj = duk_require_hobject_promote_mask(ctx, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
- key = duk_to_property_key_hstring(ctx, -1);
+ obj = duk_require_hobject_promote_mask(thr, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ key = duk_to_property_key_hstring(thr, -1);
DUK_ASSERT(key != NULL);
DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- rc = duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE);
- if (!rc) {
- duk_push_undefined(ctx);
- duk_remove_m2(ctx);
+ if (!duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE)) {
+ duk_push_undefined(thr);
+ duk_remove_m2(thr);
return;
}
- duk_push_object(ctx);
+ duk_push_object(thr);
/* [ ... key value desc ] */
@@ -56449,32 +57949,32 @@ DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_context *ct
* still have the property present with the value 'undefined'.
*/
if (pd.get) {
- duk_push_hobject(ctx, pd.get);
+ duk_push_hobject(thr, pd.get);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_GET);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_GET);
if (pd.set) {
- duk_push_hobject(ctx, pd.set);
+ duk_push_hobject(thr, pd.set);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_SET);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_SET);
} else {
- duk_dup_m2(ctx);
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_VALUE);
- duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_WRITABLE);
+ duk_dup_m2(thr);
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_VALUE);
+ duk_push_boolean(thr, DUK_PROPDESC_IS_WRITABLE(&pd));
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_WRITABLE);
}
- duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_ENUMERABLE);
- duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
- duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_CONFIGURABLE);
+ duk_push_boolean(thr, DUK_PROPDESC_IS_ENUMERABLE(&pd));
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_ENUMERABLE);
+ duk_push_boolean(thr, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
+ duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_CONFIGURABLE);
/* [ ... key value desc ] */
- duk_replace(ctx, -3);
- duk_pop(ctx); /* -> [ ... desc ] */
+ duk_replace(thr, -3);
+ duk_pop_unsafe(thr); /* -> [ ... desc ] */
}
/*
@@ -56494,13 +57994,12 @@ DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_context *ct
/* XXX: very basic optimization -> duk_get_prop_stridx_top */
DUK_INTERNAL
-void duk_hobject_prepare_property_descriptor(duk_context *ctx,
+void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
duk_idx_t idx_in,
duk_uint_t *out_defprop_flags,
duk_idx_t *out_idx_value,
duk_hobject **out_getter,
duk_hobject **out_setter) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_idx_t idx_value = -1;
duk_hobject *getter = NULL;
duk_hobject *setter = NULL;
@@ -56508,7 +58007,6 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
duk_bool_t is_acc_desc = 0;
duk_uint_t defprop_flags = 0;
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(out_defprop_flags != NULL);
DUK_ASSERT(out_idx_value != NULL);
DUK_ASSERT(out_getter != NULL);
@@ -56516,8 +58014,8 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
DUK_ASSERT(idx_in <= 0x7fffL); /* short variants would be OK, but not used to avoid shifts */
/* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
- idx_in = duk_require_normalize_index(ctx, idx_in);
- (void) duk_require_hobject(ctx, idx_in);
+ idx_in = duk_require_normalize_index(thr, idx_in);
+ (void) duk_require_hobject(thr, idx_in);
/* The coercion order must match the ToPropertyDescriptor() algorithm
* so that side effects in coercion happen in the correct order.
@@ -56525,23 +58023,23 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
* although it doesn't matter in practice.)
*/
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_VALUE)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_VALUE)) {
is_data_desc = 1;
defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
- idx_value = duk_get_top_index(ctx);
+ idx_value = duk_get_top_index(thr);
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) {
is_data_desc = 1;
- if (duk_to_boolean(ctx, -1)) {
+ if (duk_to_boolean(thr, -1)) {
defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
}
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_GET)) {
- duk_tval *tv = duk_require_tval(ctx, -1);
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_GET)) {
+ duk_tval *tv = duk_require_tval(thr, -1);
duk_hobject *h_get;
if (DUK_TVAL_IS_UNDEFINED(tv)) {
@@ -56552,7 +58050,7 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
* lightfuncs don't fit into a property value slot. This
* has some side effects, see test-dev-lightfunc-accessor.js.
*/
- h_get = duk_get_hobject_promote_lfunc(ctx, -1);
+ h_get = duk_get_hobject_promote_lfunc(thr, -1);
if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
goto type_error;
}
@@ -56562,8 +58060,8 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_SET)) {
- duk_tval *tv = duk_require_tval(ctx, -1);
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_SET)) {
+ duk_tval *tv = duk_require_tval(thr, -1);
duk_hobject *h_set;
if (DUK_TVAL_IS_UNDEFINED(tv)) {
@@ -56574,7 +58072,7 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
* lightfuncs don't fit into a property value slot. This
* has some side effects, see test-dev-lightfunc-accessor.js.
*/
- h_set = duk_get_hobject_promote_lfunc(ctx, -1);
+ h_set = duk_get_hobject_promote_lfunc(thr, -1);
if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
goto type_error;
}
@@ -56584,16 +58082,16 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_ENUMERABLE)) {
- if (duk_to_boolean(ctx, -1)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) {
+ if (duk_to_boolean(thr, -1)) {
defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
}
}
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_CONFIGURABLE)) {
- if (duk_to_boolean(ctx, -1)) {
+ if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) {
+ if (duk_to_boolean(thr, -1)) {
defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
@@ -56637,7 +58135,7 @@ void duk_hobject_prepare_property_descriptor(duk_context *ctx,
/* XXX: this is a major target for size optimization */
DUK_INTERNAL
-duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
+duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
duk_uint_t defprop_flags,
duk_hobject *obj,
duk_hstring *key,
@@ -56645,7 +58143,6 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
duk_hobject *get,
duk_hobject *set,
duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
duk_uint32_t arr_idx;
duk_tval tv;
duk_bool_t has_enumerable;
@@ -56667,7 +58164,6 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(key != NULL);
/* idx_value may be < 0 (no value), set and get may be NULL */
@@ -56704,7 +58200,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
(long) has_enumerable, (long) is_enumerable,
(long) has_configurable, (long) is_configurable,
(long) has_writable, (long) is_writable,
- (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(ctx, idx_value) : NULL),
+ (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(thr, idx_value) : NULL),
(long) has_get, (void *) get, (duk_heaphdr *) get,
(long) has_set, (void *) set, (duk_heaphdr *) set,
(long) arr_idx, (long) throw_flag));
@@ -56739,9 +58235,9 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
arrlen_old_len = a->length;
DUK_ASSERT(idx_value >= 0);
- arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(ctx, idx_value));
- duk_push_u32(ctx, arrlen_new_len);
- duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
+ arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(thr, idx_value));
+ duk_push_u32(thr, arrlen_new_len);
+ duk_replace(thr, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
@@ -56870,7 +58366,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
}
/* write to entry part */
- e_idx = duk__alloc_entry_checked(thr, obj, key);
+ e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
DUK_ASSERT(e_idx >= 0);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
@@ -56900,7 +58396,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
}
if (has_value) {
- duk_tval *tv_tmp = duk_require_tval(ctx, idx_value);
+ duk_tval *tv_tmp = duk_require_tval(thr, idx_value);
DUK_TVAL_SET_TVAL(&tv, tv_tmp);
} else {
DUK_TVAL_SET_UNDEFINED(&tv); /* default value */
@@ -56923,7 +58419,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
}
/* write to entry part */
- e_idx = duk__alloc_entry_checked(thr, obj, key);
+ e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
DUK_ASSERT(e_idx >= 0);
tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
DUK_TVAL_SET_TVAL(tv2, &tv);
@@ -56976,8 +58472,8 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
goto need_check;
}
- tmp1 = duk_require_tval(ctx, -1); /* curr value */
- tmp2 = duk_require_tval(ctx, idx_value); /* new value */
+ tmp1 = duk_require_tval(thr, -1); /* curr value */
+ tmp2 = duk_require_tval(thr, idx_value); /* new value */
if (!duk_js_samevalue(tmp1, tmp2)) {
goto need_check;
}
@@ -57096,7 +58592,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
if (curr.a_idx >= 0) {
DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
duk__abandon_array_checked(thr, obj);
- duk_pop(ctx); /* remove old value */
+ duk_pop_unsafe(thr); /* remove old value */
rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
DUK_UNREF(rc);
DUK_ASSERT(rc != 0);
@@ -57172,8 +58668,8 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
}
/* Note: changing from writable to non-writable is OK */
if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
- duk_tval *tmp1 = duk_require_tval(ctx, -1); /* curr value */
- duk_tval *tmp2 = duk_require_tval(ctx, idx_value); /* new value */
+ duk_tval *tmp1 = duk_require_tval(thr, -1); /* curr value */
+ duk_tval *tmp2 = duk_require_tval(thr, idx_value); /* new value */
if (!duk_js_samevalue(tmp1, tmp2)) {
goto fail_not_configurable;
}
@@ -57244,7 +58740,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
DUK_ASSERT(!has_get);
DUK_ASSERT(idx_value >= 0); /* must be: if attributes match and we get here the value must differ (otherwise no change) */
- tv2 = duk_require_tval(ctx, idx_value);
+ tv2 = duk_require_tval(thr, idx_value);
tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate a_idx */
goto success_exotics;
@@ -57252,7 +58748,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
duk__abandon_array_checked(thr, obj);
- duk_pop(ctx); /* remove old value */
+ duk_pop_unsafe(thr); /* remove old value */
rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
DUK_UNREF(rc);
DUK_ASSERT(rc != 0);
@@ -57332,7 +58828,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
if (curr.e_idx >= 0) {
DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- tv2 = duk_require_tval(ctx, idx_value);
+ tv2 = duk_require_tval(thr, idx_value);
tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate e_idx */
} else {
@@ -57462,17 +58958,17 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
"update bound value (variable/argument)"));
- varname = duk_require_hstring(ctx, -1);
+ varname = duk_require_hstring(thr, -1);
DUK_ASSERT(varname != NULL);
DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
"key=%!O, varname=%!O, value=%!T",
(duk_heaphdr *) key,
(duk_heaphdr *) varname,
- (duk_tval *) duk_require_tval(ctx, idx_value)));
+ (duk_tval *) duk_require_tval(thr, idx_value)));
/* strict flag for putvar comes from our caller (currently: fixed) */
- duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, idx_value), 1 /*throw_flag*/);
+ duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, idx_value), 1 /*throw_flag*/);
}
if (has_writable && !is_writable) {
DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
@@ -57512,23 +59008,22 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
* Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
*/
-DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags) {
duk_hstring *h_v;
duk_hobject *h_obj;
duk_propdesc desc;
duk_bool_t ret;
/* coercion order matters */
- h_v = duk_to_hstring_acceptsymbol(ctx, 0);
+ h_v = duk_to_hstring_acceptsymbol(thr, 0);
DUK_ASSERT(h_v != NULL);
- h_obj = duk_push_this_coercible_to_object(ctx);
+ h_obj = duk_push_this_coercible_to_object(thr);
DUK_ASSERT(h_obj != NULL);
ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */
- duk_push_boolean(ctx, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
+ duk_push_boolean(thr, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
return 1;
}
@@ -57694,7 +59189,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk
DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */
DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
- boff = duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
+ boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
(long) pos, (long) boff, (duk_heaphdr *) h));
DUK_ASSERT_DISABLE(boff >= 0);
@@ -57719,7 +59214,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk
cp2 = 0; /* If call fails, this is left untouched and won't match cp2 check. */
(void) duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp2);
if (cp2 >= 0xdc00UL && cp2 <= 0xdfffUL) {
- cp1 = ((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL;
+ cp1 = (duk_ucodepoint_t) (((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL);
}
}
} else {
@@ -57730,9 +59225,46 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk
}
/*
- * duk_hstring charlen access
+ * duk_hstring charlen, when lazy charlen disabled
+ */
+
+#if !defined(DUK_USE_HSTRING_LAZY_CLEN)
+#if !defined(DUK_USE_HSTRING_CLEN)
+#error non-lazy duk_hstring charlen but DUK_USE_HSTRING_CLEN not set
+#endif
+DUK_INTERNAL void duk_hstring_init_charlen(duk_hstring *h) {
+ duk_uint32_t clen;
+
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(h));
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
+
+ clen = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+#if defined(DUK_USE_STRLEN16)
+ DUK_ASSERT(clen <= 0xffffUL); /* Bytelength checked during interning. */
+ h->clen16 = (duk_uint16_t) clen;
+#else
+ h->clen = (duk_uint32_t) clen;
+#endif
+ if (DUK_LIKELY(clen == DUK_HSTRING_GET_BYTELEN(h))) {
+ DUK_HSTRING_SET_ASCII(h);
+ }
+}
+
+DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
+#if defined(DUK_USE_STRLEN16)
+ return h->clen16;
+#else
+ return h->clen;
+#endif
+}
+#endif /* !DUK_USE_HSTRING_LAZY_CLEN */
+
+/*
+ * duk_hstring charlen, when lazy charlen enabled
*/
+#if defined(DUK_USE_HSTRING_LAZY_CLEN)
#if defined(DUK_USE_HSTRING_CLEN)
DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) {
duk_size_t res;
@@ -57810,6 +59342,27 @@ DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
return duk__hstring_get_charlen_slowpath(h);
}
#endif /* DUK_USE_HSTRING_CLEN */
+#endif /* DUK_USE_HSTRING_LAZY_CLEN */
+
+/*
+ * Compare duk_hstring to an ASCII cstring.
+ */
+
+DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr) {
+ duk_size_t len;
+
+ DUK_ASSERT(h != NULL);
+ DUK_ASSERT(cstr != NULL);
+
+ len = DUK_STRLEN(cstr);
+ if (len != DUK_HSTRING_GET_BYTELEN(h)) {
+ return 0;
+ }
+ if (DUK_MEMCMP((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) {
+ return 1;
+ }
+ return 0;
+}
/*
* duk_hthread allocation and freeing.
*/
@@ -57830,23 +59383,21 @@ DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->valstack == NULL);
DUK_ASSERT(thr->valstack_end == NULL);
+ DUK_ASSERT(thr->valstack_alloc_end == NULL);
DUK_ASSERT(thr->valstack_bottom == NULL);
DUK_ASSERT(thr->valstack_top == NULL);
- DUK_ASSERT(thr->callstack == NULL);
DUK_ASSERT(thr->callstack_curr == NULL);
- DUK_ASSERT(thr->catchstack == NULL);
/* valstack */
+ DUK_ASSERT(DUK_VALSTACK_API_ENTRY_MINIMUM <= DUK_VALSTACK_INITIAL_SIZE);
alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
if (!thr->valstack) {
goto fail;
}
DUK_MEMZERO(thr->valstack, alloc_size);
- thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
-#if !defined(DUK_USE_PREFER_SIZE)
- thr->valstack_size = DUK_VALSTACK_INITIAL_SIZE;
-#endif
+ thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM;
+ thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
thr->valstack_bottom = thr->valstack;
thr->valstack_top = thr->valstack;
@@ -57854,37 +59405,13 @@ DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr
DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
}
- /* callstack */
- alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
- thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
- if (!thr->callstack) {
- goto fail;
- }
- DUK_MEMZERO(thr->callstack, alloc_size);
- thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
- DUK_ASSERT(thr->callstack_top == 0);
- DUK_ASSERT(thr->callstack_curr == NULL);
-
- /* catchstack */
- alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
- thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
- if (!thr->catchstack) {
- goto fail;
- }
- DUK_MEMZERO(thr->catchstack, alloc_size);
- thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
- DUK_ASSERT(thr->catchstack_top == 0);
-
return 1;
fail:
DUK_FREE(heap, thr->valstack);
- DUK_FREE(heap, thr->callstack);
- DUK_FREE(heap, thr->catchstack);
+ DUK_ASSERT(thr->callstack_curr == NULL);
thr->valstack = NULL;
- thr->callstack = NULL;
- thr->catchstack = NULL;
return 0;
}
@@ -57895,18 +59422,6 @@ DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
DUK_UNREF(heap);
return (void *) thr->valstack;
}
-
-DUK_INTERNAL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud) {
- duk_hthread *thr = (duk_hthread *) ud;
- DUK_UNREF(heap);
- return (void *) thr->callstack;
-}
-
-DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
- duk_hthread *thr = (duk_hthread *) ud;
- DUK_UNREF(heap);
- return (void *) thr->catchstack;
-}
/*
* Initialize built-in objects. Current thread must have a valstack
* and initialization errors may longjmp, so a setjmp() catch point
@@ -57943,7 +59458,6 @@ DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
#if defined(DUK_USE_ROM_OBJECTS)
#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
- duk_context *ctx;
duk_hobject *h_global;
#if defined(DUK_USE_ROM_GLOBAL_CLONE)
duk_hobject *h_oldglobal;
@@ -57952,13 +59466,11 @@ DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
#endif
duk_hobject *h_objenv;
- ctx = (duk_context *) thr;
-
/* XXX: refactor into internal helper, duk_clone_hobject() */
#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
/* Inherit from ROM-based global object: less RAM usage, less transparent. */
- h_global = duk_push_object_helper(ctx,
+ h_global = duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
@@ -57969,7 +59481,7 @@ DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
* fully RAM-based global object. Uses more memory than the inherit
* model but more compliant.
*/
- h_global = duk_push_object_helper(ctx,
+ h_global = duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
@@ -58020,7 +59532,7 @@ DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
DUK_ASSERT(h_objenv != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL);
- duk_push_hobject(ctx, h_objenv);
+ duk_push_hobject(thr, h_objenv);
DUK_ASSERT(h_global != NULL);
((duk_hobjenv *) h_objenv)->target = h_global;
@@ -58035,7 +59547,7 @@ DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv);
- duk_pop_2(ctx); /* Pop global object and global env. */
+ duk_pop_2(thr); /* Pop global object and global env. */
}
#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
@@ -58062,15 +59574,15 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#endif
}
#else /* DUK_USE_ROM_OBJECTS */
-DUK_LOCAL void duk__push_stridx(duk_context *ctx, duk_bitdecoder_ctx *bd) {
+DUK_LOCAL void duk__push_stridx(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
duk_small_uint_t n;
n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring_stridx(ctx, n);
+ duk_push_hstring_stridx(thr, n);
}
-DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
+DUK_LOCAL void duk__push_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
/* XXX: built-ins data could provide a maximum length that is
* actually needed; bitpacked max length is now 256 bytes.
*/
@@ -58078,21 +59590,21 @@ DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
duk_small_uint_t len;
len = duk_bd_decode_bitpacked_string(bd, tmp);
- duk_push_lstring(ctx, (const char *) tmp, (duk_size_t) len);
+ duk_push_lstring(thr, (const char *) tmp, (duk_size_t) len);
}
-DUK_LOCAL void duk__push_stridx_or_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
+DUK_LOCAL void duk__push_stridx_or_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
duk_small_uint_t n;
n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
if (n == 0) {
- duk__push_string(ctx, bd);
+ duk__push_string(thr, bd);
} else {
n--;
DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring_stridx(ctx, n);
+ duk_push_hstring_stridx(thr, n);
}
}
-DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
+DUK_LOCAL void duk__push_double(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
duk_double_union du;
duk_small_uint_t i;
@@ -58103,11 +59615,10 @@ DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
}
- duk_push_number(ctx, du.d); /* push operation normalizes NaNs */
+ duk_push_number(thr, du.d); /* push operation normalizes NaNs */
}
DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_bitdecoder_ctx bd_ctx;
duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
duk_hobject *h;
@@ -58130,12 +59641,14 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
* into thr->builtins[]. These are objects referenced in some way
* from thr->builtins[] roots but which don't need to be indexed by
* Duktape through thr->builtins[] (e.g. user custom objects).
+ *
+ * Internal prototypes will be incorrect (NULL) at this stage.
*/
- duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS);
+ duk_require_stack(thr, DUK_NUM_ALL_BUILTINS);
DUK_DD(DUK_DDPRINT("create empty built-ins"));
- DUK_ASSERT_TOP(ctx, 0);
+ DUK_ASSERT_TOP(thr, 0);
for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
duk_small_uint_t class_num;
duk_small_int_t len = -1; /* must be signed */
@@ -58163,9 +59676,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
}
/* XXX: set magic directly here? (it could share the c_nargs arg) */
- duk_push_c_function_noexotic(ctx, c_func, c_nargs);
-
- h = duk_known_hobject(ctx, -1);
+ (void) duk_push_c_function_builtin(thr, c_func, c_nargs);
+ h = duk_known_hobject(thr, -1);
/* Currently all built-in native functions are strict.
* duk_push_c_function() now sets strict flag, so
@@ -58175,14 +59687,14 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/* XXX: function properties */
- duk__push_stridx_or_string(ctx, bd);
+ duk__push_stridx_or_string(thr, bd);
#if defined(DUK_USE_FUNC_NAME_PROPERTY)
- duk_xdef_prop_stridx_short(ctx,
+ duk_xdef_prop_stridx_short(thr,
-2,
DUK_STRIDX_NAME,
DUK_PROPDESC_FLAGS_C);
#else
- duk_pop(ctx); /* Not very ideal but good enough for now. */
+ duk_pop(thr); /* Not very ideal but good enough for now. */
#endif
/* Almost all global level Function objects are constructable
@@ -58199,7 +59711,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
magic = (duk_int16_t) duk_bd_decode_varuint(bd);
((duk_hnatfunc *) h)->magic = magic;
} else if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
- duk_push_array(ctx);
+ duk_push_array(thr);
} else if (class_num == DUK_HOBJECT_CLASS_OBJENV) {
duk_hobjenv *env;
duk_hobject *global;
@@ -58211,9 +59723,9 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
DUK_ASSERT(env->target == NULL);
- duk_push_hobject(ctx, (duk_hobject *) env);
+ duk_push_hobject(thr, (duk_hobject *) env);
- global = duk_known_hobject(ctx, DUK_BIDX_GLOBAL);
+ global = duk_known_hobject(thr, DUK_BIDX_GLOBAL);
DUK_ASSERT(global != NULL);
env->target = global;
DUK_HOBJECT_INCREF(thr, global);
@@ -58223,14 +59735,14 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
} else {
DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV);
- (void) duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_FLAG_EXTENSIBLE,
-1); /* no prototype or class yet */
}
- h = duk_known_hobject(ctx, -1);
+ h = duk_known_hobject(thr, -1);
DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
if (i < DUK_NUM_BUILTINS) {
@@ -58250,8 +59762,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
*/
DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */
- duk_push_int(ctx, len);
- duk_xdef_prop_stridx_short(ctx,
+ duk_push_int(thr, len);
+ duk_xdef_prop_stridx_short(thr,
-2,
DUK_STRIDX_LENGTH,
DUK_PROPDESC_FLAGS_C);
@@ -58289,7 +59801,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/*
* Then decode the builtins init data (see genbuiltins.py) to
- * init objects
+ * init objects. Internal prototypes are set at this stage,
+ * with thr->builtins[] populated.
*/
DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
@@ -58298,13 +59811,20 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_small_uint_t num;
DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
- h = duk_known_hobject(ctx, i);
+ h = duk_known_hobject(thr, (duk_idx_t) i);
t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
if (t > 0) {
t--;
DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(ctx, t));
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(thr, (duk_idx_t) t));
+ } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
+ /* Standard native built-ins cannot inherit from
+ * %NativeFunctionPrototype%, they are required to
+ * inherit from Function.prototype directly.
+ */
+ DUK_ASSERT(thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE] != NULL);
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
}
t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
@@ -58316,7 +59836,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
*/
t--;
DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
- duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup(thr, (duk_idx_t) t);
+ duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_NONE);
}
t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
@@ -58328,7 +59849,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
*/
t--;
DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
- duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
+ duk_dup(thr, (duk_idx_t) t);
+ duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);
}
/* normal valued properties */
@@ -58337,7 +59859,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
for (j = 0; j < num; j++) {
duk_small_uint_t defprop_flags;
- duk__push_stridx_or_string(ctx, bd);
+ duk__push_stridx_or_string(thr, bd);
/*
* Property attribute defaults are defined in E5 Section 15 (first
@@ -58367,38 +59889,38 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
- (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) defprop_flags, (long) t));
+ (long) i, (long) j, duk_get_tval(thr, -1), (unsigned long) defprop_flags, (long) t));
switch (t) {
case DUK__PROP_TYPE_DOUBLE: {
- duk__push_double(ctx, bd);
+ duk__push_double(thr, bd);
break;
}
case DUK__PROP_TYPE_STRING: {
- duk__push_string(ctx, bd);
+ duk__push_string(thr, bd);
break;
}
case DUK__PROP_TYPE_STRIDX: {
- duk__push_stridx(ctx, bd);
+ duk__push_stridx(thr, bd);
break;
}
case DUK__PROP_TYPE_BUILTIN: {
duk_small_uint_t bidx;
bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
- duk_dup(ctx, (duk_idx_t) bidx);
+ duk_dup(thr, (duk_idx_t) bidx);
break;
}
case DUK__PROP_TYPE_UNDEFINED: {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
break;
}
case DUK__PROP_TYPE_BOOLEAN_TRUE: {
- duk_push_true(ctx);
+ duk_push_true(thr);
break;
}
case DUK__PROP_TYPE_BOOLEAN_FALSE: {
- duk_push_false(ctx);
+ duk_push_false(thr);
break;
}
case DUK__PROP_TYPE_ACCESSOR: {
@@ -58409,18 +59931,18 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_c_function c_func_setter;
DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
- (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags));
+ (long) i, duk_get_tval(thr, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags));
c_func_getter = duk_bi_native_functions[natidx_getter];
if (c_func_getter != NULL) {
- duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
- duk_set_magic(ctx, -1, (duk_int_t) accessor_magic);
+ duk_push_c_function_builtin_noconstruct(thr, c_func_getter, 0); /* always 0 args */
+ duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
}
c_func_setter = duk_bi_native_functions[natidx_setter];
if (c_func_setter != NULL) {
- duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
- duk_set_magic(ctx, -1, (duk_int_t) accessor_magic);
+ duk_push_c_function_builtin_noconstruct(thr, c_func_setter, 1); /* always 1 arg */
+ duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
}
@@ -58437,8 +59959,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
}
}
- duk_def_prop(ctx, i, defprop_flags);
- DUK_ASSERT_TOP(ctx, DUK_NUM_ALL_BUILTINS);
+ duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
+ DUK_ASSERT_TOP(thr, DUK_NUM_ALL_BUILTINS);
}
/* native function properties */
@@ -58456,13 +59978,13 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_small_int_t lightfunc_eligible;
#endif
- duk__push_stridx_or_string(ctx, bd);
- h_key = duk_known_hstring(ctx, -1);
+ duk__push_stridx_or_string(thr, bd);
+ h_key = duk_known_hstring(thr, -1);
DUK_UNREF(h_key);
natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
- c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
+ c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_uint32_t) c_length /*def_value*/);
if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
c_nargs = DUK_VARARGS;
}
@@ -58482,24 +60004,33 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
(c_length <= DUK_LFUNC_LENGTH_MAX) &&
(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
- if (h_key == DUK_HTHREAD_STRING_EVAL(thr) ||
- h_key == DUK_HTHREAD_STRING_YIELD(thr) ||
- h_key == DUK_HTHREAD_STRING_RESUME(thr)) {
- /* These functions have trouble working as lightfuncs.
- * Some of them have specific asserts and some may have
- * additional properties (e.g. 'require.id' may be written).
- */
- DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j));
+ /* These functions have trouble working as lightfuncs.
+ * Some of them have specific asserts and some may have
+ * additional properties (e.g. 'require.id' may be written).
+ */
+ if (c_func == duk_bi_global_object_eval) {
+ lightfunc_eligible = 0;
+ }
+#if defined(DUK_USE_COROUTINE_SUPPORT)
+ if (c_func == duk_bi_thread_yield ||
+ c_func == duk_bi_thread_resume) {
+ lightfunc_eligible = 0;
+ }
+#endif
+ if (c_func == duk_bi_function_prototype_call ||
+ c_func == duk_bi_function_prototype_apply ||
+ c_func == duk_bi_reflect_apply ||
+ c_func == duk_bi_reflect_construct) {
lightfunc_eligible = 0;
}
if (lightfunc_eligible) {
duk_tval tv_lfunc;
- duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
+ duk_small_uint_t lf_nargs = (duk_small_uint_t) (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
- duk_push_tval(ctx, &tv_lfunc);
- DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(ctx, -1)));
+ duk_push_tval(thr, &tv_lfunc);
+ DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(thr, -1)));
goto lightfunc_skip;
}
@@ -58508,10 +60039,21 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/* [ (builtin objects) name ] */
- duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs);
- h_func = duk_known_hnatfunc(ctx, -1);
+ duk_push_c_function_builtin_noconstruct(thr, c_func, c_nargs);
+ h_func = duk_known_hnatfunc(thr, -1);
DUK_UNREF(h_func);
+ /* XXX: add into init data? */
+
+ /* Special call handling, not described in init data. */
+ if (c_func == duk_bi_global_object_eval ||
+ c_func == duk_bi_function_prototype_call ||
+ c_func == duk_bi_function_prototype_apply ||
+ c_func == duk_bi_reflect_apply ||
+ c_func == duk_bi_reflect_construct) {
+ DUK_HOBJECT_SET_SPECIAL_CALL((duk_hobject *) h_func);
+ }
+
/* Currently all built-in native functions are strict.
* This doesn't matter for many functions, but e.g.
* String.prototype.charAt (and other string functions)
@@ -58532,16 +60074,16 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
/* [ (builtin objects) name func ] */
- duk_push_int(ctx, c_length);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
+ duk_push_uint(thr, c_length);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
- duk_dup_m2(ctx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
+ duk_dup_m2(thr);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
/* XXX: other properties of function instances; 'arguments', 'caller'. */
DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
- (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1)));
+ (long) i, (long) j, (duk_tval *) duk_get_tval(thr, -1)));
/* [ (builtin objects) name func ] */
@@ -58554,7 +60096,10 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
lightfunc_skip:
#endif
- duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC);
+ /* XXX: So far all ES builtins are 'wc' but e.g.
+ * performance.now() should be 'wec'.
+ */
+ duk_xdef_prop(thr, (duk_idx_t) i, DUK_PROPDESC_FLAGS_WC);
/* [ (builtin objects) ] */
}
@@ -58578,11 +60123,11 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
*/
#if defined(DUK_USE_DATE_BUILTIN)
- duk_get_prop_stridx_short(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
- duk_xdef_prop_stridx_short(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
+ duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
+ duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
#endif
- h = duk_known_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
+ h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR);
DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
@@ -58596,7 +60141,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#endif
/* XXX: relocate */
- duk_push_string(ctx,
+ duk_push_string(thr,
/* Endianness indicator */
#if defined(DUK_USE_INTEGER_LE)
"l"
@@ -58697,7 +60242,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
DUK_USE_OS_STRING
" "
DUK_USE_COMPILER_STRING);
- duk_xdef_prop_stridx_short(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
+ duk_xdef_prop_stridx_short(thr, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
/*
* Since built-ins are not often extended, compact them.
@@ -58705,7 +60250,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
DUK_DD(DUK_DDPRINT("compact built-ins"));
for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
- duk_hobject_compact_props(thr, duk_known_hobject(ctx, i));
+ duk_hobject_compact_props(thr, duk_known_hobject(thr, (duk_idx_t) i));
}
DUK_D(DUK_DPRINT("INITBUILTINS END"));
@@ -58713,7 +60258,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
- (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i)));
+ (long) i, (duk_heaphdr *) duk_require_hobject(thr, i)));
}
#endif
@@ -58723,8 +60268,8 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
* through builtins[].
*/
- duk_set_top(ctx, 0);
- DUK_ASSERT_TOP(ctx, 0);
+ duk_set_top(thr, 0);
+ DUK_ASSERT_TOP(thr, 0);
}
#endif /* DUK_USE_ROM_OBJECTS */
@@ -58760,29 +60305,25 @@ DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_ht
DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
- /* Order of unwinding is important */
-
- duk_hthread_catchstack_unwind(thr, 0);
- duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */
+ while (thr->callstack_curr != NULL) {
+ duk_hthread_activation_unwind_norz(thr);
+ }
thr->valstack_bottom = thr->valstack;
- duk_set_top((duk_context *) thr, 0); /* unwinds valstack, updating refcounts */
+ duk_set_top(thr, 0); /* unwinds valstack, updating refcounts */
thr->state = DUK_HTHREAD_STATE_TERMINATED;
/* Here we could remove references to built-ins, but it may not be
* worth the effort because built-ins are quite likely to be shared
* with another (unterminated) thread, and terminated threads are also
- * usually garbage collected quite quickly. Also, doing DECREFs
- * could trigger finalization, which would run on the current thread
- * and have access to only some of the built-ins. Garbage collection
- * deals with this correctly already.
+ * usually garbage collected quite quickly.
+ *
+ * We could also shrink the value stack here, but that also may not
+ * be worth the effort for the same reason.
*/
- /* XXX: Shrink the stacks to minimize memory usage? May not
- * be worth the effort because terminated threads are usually
- * garbage collected quite soon.
- */
+ DUK_REFZERO_CHECK_SLOW(thr);
}
#if defined(DUK_USE_DEBUGGER_SUPPORT)
@@ -58853,585 +60394,411 @@ DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
}
}
/*
- * Manipulation of thread stacks (valstack, callstack, catchstack).
- *
- * Ideally unwinding of stacks should have no side effects, which would
- * then favor separate unwinding and shrink check primitives for each
- * stack type. A shrink check may realloc and thus have side effects.
- *
- * However, currently callstack unwinding itself has side effects, as it
- * needs to DECREF multiple objects, close environment records, etc.
- * Stacks must thus be unwound in the correct order by the caller.
- *
- * (XXX: This should be probably reworked so that there is a shared
- * unwind primitive which handles all stacks as requested, and knows
- * the proper order for unwinding.)
- *
- * Valstack entries above 'top' are always kept initialized to
- * "undefined unused". Callstack and catchstack entries above 'top'
- * are not zeroed and are left as garbage.
+ * Thread stack (mainly call stack) primitives: allocation of activations,
+ * unwinding catchers and activations, etc.
*
- * Value stack handling is mostly a part of the API implementation.
+ * Value stack handling is a part of the API implementation.
*/
/* #include duk_internal.h -> already included */
-DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_grow(duk_hthread *thr) {
- duk_activation *new_ptr;
- duk_size_t old_size;
- duk_size_t new_size;
+/* Unwind the topmost catcher of the current activation (caller must check that
+ * both exist) without side effects.
+ */
+DUK_INTERNAL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act) {
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
-
- old_size = thr->callstack_size;
- new_size = old_size + DUK_CALLSTACK_GROW_STEP;
-
- /* this is a bit approximate (errors out before max is reached); this is OK */
- if (new_size >= thr->callstack_max) {
- DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
- }
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL); /* caller must check */
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
- DUK_DD(DUK_DDPRINT("growing callstack %ld -> %ld", (long) old_size, (long) new_size));
+ DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is done)", (void *) cat));
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
+ if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
+ duk_hobject *env;
- DUK_ASSERT(new_size > 0);
- new_ptr = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
- if (!new_ptr) {
- /* No need for a NULL/zero-size check because new_size > 0) */
- DUK_ERROR_ALLOC_FAILED(thr);
- }
- thr->callstack = new_ptr;
- thr->callstack_size = new_size;
+ env = act->lex_env; /* current lex_env of the activation (created for catcher) */
+ DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
+ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
+ DUK_HOBJECT_INCREF(thr, act->lex_env);
+ DUK_HOBJECT_DECREF_NORZ(thr, env);
- if (thr->callstack_top > 0) {
- thr->callstack_curr = thr->callstack + thr->callstack_top - 1;
- } else {
- thr->callstack_curr = NULL;
+ /* There is no need to decref anything else than 'env': if 'env'
+ * becomes unreachable, refzero will handle decref'ing its prototype.
+ */
}
- /* note: any entries above the callstack top are garbage and not zeroed */
-}
-
-/* check that there is space for at least one new entry */
-DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
-
- if (DUK_LIKELY(thr->callstack_top < thr->callstack_size)) {
- return;
- }
- duk__hthread_do_callstack_grow(thr);
+ act->cat = cat->parent;
+ duk_hthread_catcher_free(thr, cat);
}
-DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_callstack_shrink(duk_hthread *thr) {
- duk_size_t new_size;
- duk_activation *p;
+/* Same as above, but caller is certain no catcher-related lexenv may exist. */
+DUK_INTERNAL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act) {
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
-
- new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
- DUK_ASSERT(new_size >= thr->callstack_top);
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL); /* caller must check */
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
- DUK_DD(DUK_DDPRINT("shrinking callstack %ld -> %ld", (long) thr->callstack_size, (long) new_size));
+ DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is not done)", (void *) cat));
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
+ DUK_ASSERT(!DUK_CAT_HAS_LEXENV_ACTIVE(cat));
- /* shrink failure is not fatal */
- p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
- if (p) {
- thr->callstack = p;
- thr->callstack_size = new_size;
+ act->cat = cat->parent;
+ duk_hthread_catcher_free(thr, cat);
+}
- if (thr->callstack_top > 0) {
- thr->callstack_curr = thr->callstack + thr->callstack_top - 1;
- } else {
- thr->callstack_curr = NULL;
- }
- } else {
- /* Because new_size != 0, if condition doesn't need to be
- * (p != NULL || new_size == 0).
- */
- DUK_ASSERT(new_size != 0);
- DUK_D(DUK_DPRINT("callstack shrink failed, ignoring"));
- }
+DUK_LOCAL
+#if defined(DUK_USE_CACHE_CATCHER)
+DUK_NOINLINE
+#endif
+duk_catcher *duk__hthread_catcher_alloc_slow(duk_hthread *thr) {
+ duk_catcher *cat;
- /* note: any entries above the callstack top are garbage and not zeroed */
+ cat = (duk_catcher *) DUK_ALLOC_CHECKED(thr, sizeof(duk_catcher));
+ DUK_ASSERT(cat != NULL);
+ return cat;
}
-DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
+#if defined(DUK_USE_CACHE_CATCHER)
+DUK_INTERNAL DUK_INLINE duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
+ duk_catcher *cat;
+
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
- if (DUK_LIKELY(thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD)) {
- return;
+ cat = thr->heap->catcher_free;
+ if (DUK_LIKELY(cat != NULL)) {
+ thr->heap->catcher_free = cat->parent;
+ return cat;
}
- duk__hthread_do_callstack_shrink(thr);
+ return duk__hthread_catcher_alloc_slow(thr);
}
+#else /* DUK_USE_CACHE_CATCHER */
+DUK_INTERNAL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
+ return duk__hthread_catcher_alloc_slow(thr);
+}
+#endif /* DUK_USE_CACHE_CATCHER */
-DUK_INTERNAL void duk_hthread_callstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) {
- duk_size_t idx;
-
- DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld",
- (void *) thr,
- (thr != NULL ? (long) thr->callstack_top : (long) -1),
- (long) new_top));
-
- DUK_ASSERT(thr);
- DUK_ASSERT(thr->heap);
- DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) new_top <= thr->callstack_top); /* cannot grow */
+DUK_INTERNAL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat) {
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(cat != NULL);
- /*
- * The loop below must avoid issues with potential callstack
- * reallocations. A resize (and other side effects) may happen
- * e.g. due to finalizer/errhandler calls caused by a refzero or
- * mark-and-sweep. Arbitrary finalizers may run, because when
- * an environment record is refzero'd, it may refer to arbitrary
- * values which also become refzero'd.
- *
- * So, the pointer 'p' is re-looked-up below whenever a side effect
- * might have changed it.
- */
+#if defined(DUK_USE_CACHE_CATCHER)
+ /* Unconditional caching for now; freed in mark-and-sweep. */
+ cat->parent = thr->heap->catcher_free;
+ thr->heap->catcher_free = cat;
+#else
+ DUK_FREE_CHECKED(thr, (void *) cat);
+#endif
+}
- idx = thr->callstack_top;
- while (idx > new_top) {
- duk_activation *act;
- duk_hobject *func;
- duk_hobject *tmp;
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_heap *heap;
+DUK_LOCAL
+#if defined(DUK_USE_CACHE_ACTIVATION)
+DUK_NOINLINE
#endif
+duk_activation *duk__hthread_activation_alloc_slow(duk_hthread *thr) {
+ duk_activation *act;
- idx--;
- DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) idx < thr->callstack_size); /* true, despite side effect resizes */
+ act = (duk_activation *) DUK_ALLOC_CHECKED(thr, sizeof(duk_activation));
+ DUK_ASSERT(act != NULL);
+ return act;
+}
- act = thr->callstack + idx;
- /* With lightfuncs, act 'func' may be NULL */
+#if defined(DUK_USE_CACHE_ACTIVATION)
+DUK_INTERNAL DUK_INLINE duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
+ duk_activation *act;
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- /*
- * Restore 'caller' property for non-strict callee functions.
- */
+ DUK_ASSERT(thr != NULL);
- func = DUK_ACT_GET_FUNC(act);
- if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
- duk_tval *tv_caller;
- duk_tval tv_tmp;
- duk_hobject *h_tmp;
+ act = thr->heap->activation_free;
+ if (DUK_LIKELY(act != NULL)) {
+ thr->heap->activation_free = act->parent;
+ return act;
+ }
- tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
+ return duk__hthread_activation_alloc_slow(thr);
+}
+#else /* DUK_USE_CACHE_ACTIVATION */
+DUK_INTERNAL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
+ return duk__hthread_activation_alloc_slow(thr);
+}
+#endif /* DUK_USE_CACHE_ACTIVATION */
- /* The act->prev_caller should only be set if the entry for 'caller'
- * exists (as it is only set in that case, and the property is not
- * configurable), but handle all the cases anyway.
- */
- if (tv_caller) {
- DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
- if (act->prev_caller) {
- /* Just transfer the refcount from act->prev_caller to tv_caller,
- * so no need for a refcount update. This is the expected case.
- */
- DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
- act->prev_caller = NULL;
- } else {
- DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
- DUK_ASSERT(act->prev_caller == NULL);
- }
- DUK_TVAL_DECREF_NORZ(thr, &tv_tmp);
- } else {
- h_tmp = act->prev_caller;
- if (h_tmp) {
- act->prev_caller = NULL;
- DUK_HOBJECT_DECREF_NORZ(thr, h_tmp);
- }
- }
- act = thr->callstack + idx; /* avoid side effects */
- DUK_ASSERT(act->prev_caller == NULL);
- }
-#endif
+DUK_INTERNAL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act) {
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(act != NULL);
- /*
- * Unwind debugger state. If we unwind while stepping
- * (either step over or step into), pause execution.
- */
+#if defined(DUK_USE_CACHE_ACTIVATION)
+ /* Unconditional caching for now; freed in mark-and-sweep. */
+ act->parent = thr->heap->activation_free;
+ thr->heap->activation_free = act;
+#else
+ DUK_FREE_CHECKED(thr, (void *) act);
+#endif
+}
+/* Internal helper: process the unwind for the topmost activation of a thread,
+ * but leave the duk_activation in place for possible tailcall reuse.
+ */
+DUK_LOCAL void duk__activation_unwind_nofree_norz(duk_hthread *thr) {
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- heap = thr->heap;
- if (heap->dbg_step_thread == thr &&
- heap->dbg_step_csindex == idx) {
- /* Pause for all step types: step into, step over, step out.
- * This is the only place explicitly handling a step out.
- */
- if (duk_debug_is_paused(heap)) {
- DUK_D(DUK_DPRINT("step pause trigger but already paused, ignoring"));
- } else {
- duk_debug_set_paused(heap);
- DUK_ASSERT(heap->dbg_step_thread == NULL);
- }
- }
+ duk_heap *heap;
#endif
+ duk_activation *act;
+ duk_hobject *func;
+ duk_hobject *tmp;
- /*
- * Close environment record(s) if they exist.
- *
- * Only variable environments are closed. If lex_env != var_env, it
- * cannot currently contain any register bound declarations.
- *
- * Only environments created for a NEWENV function are closed. If an
- * environment is created for e.g. an eval call, it must not be closed.
- */
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->callstack_curr != NULL); /* caller must check */
+ DUK_ASSERT(thr->callstack_top > 0);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ /* With lightfuncs, act 'func' may be NULL. */
- func = DUK_ACT_GET_FUNC(act);
- if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
- DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
- goto skip_env_close;
- }
- /* func is NULL for lightfunc */
+ /* With duk_activation records allocated separately, 'act' is a stable
+ * pointer and not affected by side effects.
+ */
- /* Catch sites are required to clean up their environments
- * in FINALLY part before propagating, so this should
- * always hold here.
- */
- DUK_ASSERT(act->lex_env == act->var_env);
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+ /*
+ * Restore 'caller' property for non-strict callee functions.
+ */
- if (act->var_env != NULL) {
- DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
- (void *) act->var_env, (duk_heaphdr *) act->var_env));
- duk_js_close_environment_record(thr, act->var_env);
- act = thr->callstack + idx; /* avoid side effect issues */
- }
+ func = DUK_ACT_GET_FUNC(act);
+ if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
+ duk_tval *tv_caller;
+ duk_tval tv_tmp;
+ duk_hobject *h_tmp;
- skip_env_close:
+ tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
- /*
- * Update preventcount
+ /* The act->prev_caller should only be set if the entry for 'caller'
+ * exists (as it is only set in that case, and the property is not
+ * configurable), but handle all the cases anyway.
*/
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- DUK_ASSERT(thr->callstack_preventcount >= 1);
- thr->callstack_preventcount--;
+ if (tv_caller) {
+ DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
+ if (act->prev_caller) {
+ /* Just transfer the refcount from act->prev_caller to tv_caller,
+ * so no need for a refcount update. This is the expected case.
+ */
+ DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
+ act->prev_caller = NULL;
+ } else {
+ DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
+ DUK_ASSERT(act->prev_caller == NULL);
+ }
+ DUK_TVAL_DECREF_NORZ(thr, &tv_tmp);
+ } else {
+ h_tmp = act->prev_caller;
+ if (h_tmp) {
+ act->prev_caller = NULL;
+ DUK_HOBJECT_DECREF_NORZ(thr, h_tmp);
+ }
}
-
- /*
- * Reference count updates, using NORZ macros so we don't
- * need to handle side effects.
- */
-
- DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env);
- act->var_env = NULL;
- DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env);
- act->lex_env = NULL;
-
- /* Note: this may cause a corner case situation where a finalizer
- * may see a currently reachable activation whose 'func' is NULL.
- */
- tmp = DUK_ACT_GET_FUNC(act);
- DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
- DUK_UNREF(tmp);
- act->func = NULL;
- }
-
- thr->callstack_top = new_top;
- if (new_top > 0) {
- thr->callstack_curr = thr->callstack + new_top - 1;
- } else {
- thr->callstack_curr = NULL;
+ DUK_ASSERT(act->prev_caller == NULL);
}
+#endif
/*
- * We could clear the book-keeping variables for the topmost activation,
- * but don't do so now.
+ * Unwind debugger state. If we unwind while stepping
+ * (for any step type), pause execution. This is the
+ * only place explicitly handling a step out.
*/
-#if 0
- if (thr->callstack_curr != NULL) {
- duk_activation *act = thr->callstack_curr;
- act->idx_retval = 0;
+
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ heap = thr->heap;
+ if (heap->dbg_pause_act == thr->callstack_curr) {
+ if (heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_EXIT) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function exit"));
+ duk_debug_set_paused(heap);
+ } else {
+ DUK_D(DUK_DPRINT("unwound past dbg_pause_act, set to NULL"));
+ heap->dbg_pause_act = NULL; /* avoid stale pointers */
+ }
+ DUK_ASSERT(heap->dbg_pause_act == NULL);
}
#endif
- /* Note: any entries above the callstack top are garbage and not zeroed.
- * Also topmost activation idx_retval is garbage (not zeroed), and must
- * be ignored.
+ /*
+ * Unwind catchers.
+ *
+ * Since there are no references in the catcher structure,
+ * unwinding is quite simple. The only thing we need to
+ * look out for is popping a possible lexical environment
+ * established for an active catch clause.
*/
-}
-
-DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) {
- duk_hthread_callstack_unwind_norz(thr, new_top);
- DUK_REFZERO_CHECK_FAST(thr);
-}
-DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_grow(duk_hthread *thr) {
- duk_catcher *new_ptr;
- duk_size_t old_size;
- duk_size_t new_size;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
-
- old_size = thr->catchstack_size;
- new_size = old_size + DUK_CATCHSTACK_GROW_STEP;
-
- /* this is a bit approximate (errors out before max is reached); this is OK */
- if (new_size >= thr->catchstack_max) {
- DUK_ERROR_RANGE(thr, DUK_STR_CATCHSTACK_LIMIT);
+ while (act->cat != NULL) {
+ duk_hthread_catcher_unwind_norz(thr, act);
}
- DUK_DD(DUK_DDPRINT("growing catchstack %ld -> %ld", (long) old_size, (long) new_size));
-
/*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
+ * Close environment record(s) if they exist.
+ *
+ * Only variable environments are closed. If lex_env != var_env, it
+ * cannot currently contain any register bound declarations.
+ *
+ * Only environments created for a NEWENV function are closed. If an
+ * environment is created for e.g. an eval call, it must not be closed.
*/
- DUK_ASSERT(new_size > 0);
- new_ptr = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
- if (!new_ptr) {
- /* No need for a NULL/zero-size check because new_size > 0) */
- DUK_ERROR_ALLOC_FAILED(thr);
+ func = DUK_ACT_GET_FUNC(act);
+ if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
+ DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
+ goto skip_env_close;
}
- thr->catchstack = new_ptr;
- thr->catchstack_size = new_size;
+ /* func is NULL for lightfunc */
- /* note: any entries above the catchstack top are garbage and not zeroed */
-}
-
-DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
+ /* Catch sites are required to clean up their environments
+ * in FINALLY part before propagating, so this should
+ * always hold here.
+ */
+ DUK_ASSERT(act->lex_env == act->var_env);
- if (DUK_LIKELY(thr->catchstack_top < thr->catchstack_size)) {
- return;
+ /* XXX: Closing the environment record copies values from registers
+ * into the scope object. It's side effect free as such, but may
+ * currently run out of memory which causes an error throw. This is
+ * an actual sandboxing problem for error unwinds, and needs to be
+ * fixed e.g. by preallocating the scope property slots.
+ */
+ if (act->var_env != NULL) {
+ DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
+ (void *) act->var_env, (duk_heaphdr *) act->var_env));
+ duk_js_close_environment_record(thr, act->var_env);
}
- duk__hthread_do_catchstack_grow(thr);
-}
-
-DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__hthread_do_catchstack_shrink(duk_hthread *thr) {
- duk_size_t new_size;
- duk_catcher *p;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
-
- new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
- DUK_ASSERT(new_size >= thr->catchstack_top);
-
- DUK_DD(DUK_DDPRINT("shrinking catchstack %ld -> %ld", (long) thr->catchstack_size, (long) new_size));
+ skip_env_close:
/*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
+ * Update preventcount
*/
- /* shrink failure is not fatal */
- p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
- if (p) {
- thr->catchstack = p;
- thr->catchstack_size = new_size;
- } else {
- /* Because new_size != 0, if condition doesn't need to be
- * (p != NULL || new_size == 0).
- */
- DUK_ASSERT(new_size != 0);
- DUK_D(DUK_DPRINT("catchstack shrink failed, ignoring"));
+ if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
+ DUK_ASSERT(thr->callstack_preventcount >= 1);
+ thr->callstack_preventcount--;
}
- /* note: any entries above the catchstack top are garbage and not zeroed */
-}
-
-DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
-
- if (DUK_LIKELY(thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD)) {
- return;
- }
+ /*
+ * Reference count updates, using NORZ macros so we don't
+ * need to handle side effects.
+ *
+ * duk_activation pointers like act->var_env are intentionally
+ * left as garbage and not NULLed. Without side effects they
+ * can't be used when the values are dangling/garbage.
+ */
- duk__hthread_do_catchstack_shrink(thr);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env);
+ tmp = DUK_ACT_GET_FUNC(act);
+ DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
+ DUK_UNREF(tmp);
}
-DUK_INTERNAL void duk_hthread_catchstack_unwind_norz(duk_hthread *thr, duk_size_t new_top) {
- duk_size_t idx;
+/* Unwind topmost duk_activation of a thread, caller must ensure that an
+ * activation exists. The call is side effect free, except that scope
+ * closure may currently throw an out-of-memory error.
+ */
+DUK_INTERNAL void duk_hthread_activation_unwind_norz(duk_hthread *thr) {
+ duk_activation *act;
- DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld",
- (void *) thr,
- (thr != NULL ? (long) thr->catchstack_top : (long) -1),
- (long) new_top));
+ duk__activation_unwind_nofree_norz(thr);
- DUK_ASSERT(thr);
- DUK_ASSERT(thr->heap);
- DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) new_top <= thr->catchstack_top); /* cannot grow */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_top > 0);
+ act = thr->callstack_curr;
+ thr->callstack_curr = act->parent;
+ thr->callstack_top--;
- /*
- * Since there are no references in the catcher structure,
- * unwinding is quite simple. The only thing we need to
- * look out for is popping a possible lexical environment
- * established for an active catch clause.
+ /* Ideally we'd restore value stack reserve here to caller's value.
+ * This doesn't work for current unwind call sites however, because
+ * the current (unwound) value stack top may be above the reserve.
+ * Thus value stack reserve is restored by the call sites.
*/
- idx = thr->catchstack_top;
- while (idx > new_top) {
- duk_catcher *p;
- duk_activation *act;
- duk_hobject *env;
-
- idx--;
- DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) idx < thr->catchstack_size);
+ /* XXX: inline for performance builds? */
+ duk_hthread_activation_free(thr, act);
- p = thr->catchstack + idx;
+ /* We could clear the book-keeping variables like retval_byteoff for
+ * the topmost activation, but don't do so now as it's not necessary.
+ */
+}
- if (DUK_CAT_HAS_LEXENV_ACTIVE(p)) {
- DUK_DDD(DUK_DDDPRINT("unwinding catchstack idx %ld, callstack idx %ld, callstack top %ld: lexical environment active",
- (long) idx, (long) p->callstack_index, (long) thr->callstack_top));
+DUK_INTERNAL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr) {
+ duk__activation_unwind_nofree_norz(thr);
+}
- /* XXX: Here we have a nasty dependency: the need to manipulate
- * the callstack means that catchstack must always be unwound by
- * the caller before unwinding the callstack. This should be fixed
- * later.
- */
+/* Get duk_activation for given callstack level or NULL if level is invalid
+ * or deeper than the call stack. Level -1 refers to current activation, -2
+ * to its caller, etc. Starting from Duktape 2.2 finding the activation is
+ * a linked list scan which gets more expensive the deeper the lookup is.
+ */
+DUK_INTERNAL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level) {
+ duk_activation *act;
- /* Note that multiple catchstack entries may refer to the same
- * callstack entry.
- */
- act = thr->callstack + p->callstack_index;
- DUK_ASSERT(act >= thr->callstack);
- DUK_ASSERT(act < thr->callstack + thr->callstack_top);
-
- DUK_DDD(DUK_DDDPRINT("catchstack_index=%ld, callstack_index=%ld, lex_env=%!iO",
- (long) idx, (long) p->callstack_index,
- (duk_heaphdr *) act->lex_env));
-
- env = act->lex_env; /* current lex_env of the activation (created for catcher) */
- DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
- act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
- DUK_HOBJECT_INCREF(thr, act->lex_env);
- DUK_HOBJECT_DECREF_NORZ(thr, env);
-
- /* There is no need to decref anything else than 'env': if 'env'
- * becomes unreachable, refzero will handle decref'ing its prototype.
- */
+ if (level >= 0) {
+ return NULL;
+ }
+ act = thr->callstack_curr;
+ for (;;) {
+ if (act == NULL) {
+ return act;
}
+ if (level == -1) {
+ return act;
+ }
+ level++;
+ act = act->parent;
}
-
- thr->catchstack_top = new_top;
-
- /* note: any entries above the catchstack top are garbage and not zeroed */
-}
-
-DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) {
- duk_hthread_catchstack_unwind_norz(thr, new_top);
- DUK_REFZERO_CHECK_FAST(thr);
+ /* never here */
}
#if defined(DUK_USE_FINALIZER_TORTURE)
DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) {
duk_size_t alloc_size;
duk_tval *new_ptr;
+ duk_ptrdiff_t alloc_end_off;
duk_ptrdiff_t end_off;
duk_ptrdiff_t bottom_off;
duk_ptrdiff_t top_off;
if (thr->valstack == NULL) {
+ DUK_D(DUK_DPRINT("skip valstack torture realloc, valstack is NULL"));
return;
}
+ alloc_end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack);
- alloc_size = (duk_size_t) end_off;
+ alloc_size = (duk_size_t) alloc_end_off;
if (alloc_size == 0) {
+ DUK_D(DUK_DPRINT("skip valstack torture realloc, alloc_size is zero"));
return;
}
- new_ptr = (duk_tval *) DUK_ALLOC(thr->heap, alloc_size);
+ /* Use DUK_ALLOC_RAW() to avoid side effects. */
+ new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size);
if (new_ptr != NULL) {
DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size);
DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size);
- DUK_FREE(thr->heap, (void *) thr->valstack);
+ DUK_FREE_CHECKED(thr, (void *) thr->valstack);
thr->valstack = new_ptr;
+ thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off);
thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off);
thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off);
thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off);
- /* No change in size. */
} else {
DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore"));
}
}
-
-DUK_INTERNAL void duk_hthread_callstack_torture_realloc(duk_hthread *thr) {
- duk_size_t alloc_size;
- duk_activation *new_ptr;
- duk_ptrdiff_t curr_off;
-
- if (thr->callstack == NULL) {
- return;
- }
-
- curr_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->callstack_curr - (duk_uint8_t *) thr->callstack);
- alloc_size = sizeof(duk_activation) * thr->callstack_size;
- if (alloc_size == 0) {
- return;
- }
-
- new_ptr = (duk_activation *) DUK_ALLOC(thr->heap, alloc_size);
- if (new_ptr != NULL) {
- DUK_MEMCPY((void *) new_ptr, (const void *) thr->callstack, alloc_size);
- DUK_MEMSET((void *) thr->callstack, 0x55, alloc_size);
- DUK_FREE(thr->heap, (void *) thr->callstack);
- thr->callstack = new_ptr;
- thr->callstack_curr = (duk_activation *) ((duk_uint8_t *) new_ptr + curr_off);
- /* No change in size. */
- } else {
- DUK_D(DUK_DPRINT("failed to realloc callstack for torture, ignore"));
- }
-}
-
-DUK_INTERNAL void duk_hthread_catchstack_torture_realloc(duk_hthread *thr) {
- duk_size_t alloc_size;
- duk_catcher *new_ptr;
-
- if (thr->catchstack == NULL) {
- return;
- }
-
- alloc_size = sizeof(duk_catcher) * thr->catchstack_size;
- if (alloc_size == 0) {
- return;
- }
-
- new_ptr = (duk_catcher *) DUK_ALLOC(thr->heap, alloc_size);
- if (new_ptr != NULL) {
- DUK_MEMCPY((void *) new_ptr, (const void *) thr->catchstack, alloc_size);
- DUK_MEMSET((void *) thr->catchstack, 0x55, alloc_size);
- DUK_FREE(thr->heap, (void *) thr->catchstack);
- thr->catchstack = new_ptr;
- /* No change in size. */
- } else {
- DUK_D(DUK_DPRINT("failed to realloc catchstack for torture, ignore"));
- }
-}
#endif /* DUK_USE_FINALIZER_TORTURE */
/*
* Shared helpers for arithmetic operations
@@ -59573,22 +60940,30 @@ DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
/*
* Call handling.
*
- * Main functions are:
+ * duk_handle_call_unprotected():
*
- * - duk_handle_call_unprotected(): unprotected call to Ecmascript or
- * Duktape/C function
- * - duk_handle_call_protected(): protected call to Ecmascript or
- * Duktape/C function
- * - duk_handle_safe_call(): make a protected C call within current
- * activation
- * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls
- * (not always possible), including tail calls and coroutine resume
+ * - Unprotected call to Ecmascript or Duktape/C function, from native
+ * code or bytecode executor.
*
- * See 'execution.rst'.
+ * - Also handles Ecma-to-Ecma calls which reuses a currently running
+ * executor instance to avoid native recursion. Call setup is done
+ * normally, but just before calling the bytecode executor a special
+ * return code is used to indicate that a calling executor is reused.
+ *
+ * - Also handles tailcalls, i.e. reuse of current duk_activation.
+ *
+ * - Also handles setup for initial Duktape.Thread.resume().
+ *
+ * duk_handle_safe_call():
+ *
+ * - Protected C call within current activation.
*
- * Note: setjmp() and local variables have a nasty interaction,
- * see execution.rst; non-volatile locals modified after setjmp()
- * call are not guaranteed to keep their value.
+ * setjmp() and local variables have a nasty interaction, see execution.rst;
+ * non-volatile locals modified after setjmp() call are not guaranteed to
+ * keep their value and can cause compiler or compiler version specific
+ * difficult to replicate issues.
+ *
+ * See 'execution.rst'.
*/
/* #include duk_internal.h -> already included */
@@ -59596,46 +60971,78 @@ DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
/* XXX: heap->error_not_allowed for success path too? */
/*
- * Forward declarations.
- */
-
-DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags,
- duk_idx_t idx_func);
-DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_valstack_end,
- duk_size_t entry_catchstack_top,
- duk_size_t entry_callstack_top,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc,
- duk_idx_t idx_func,
- duk_jmpbuf *old_jmpbuf_ptr);
-DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
- duk_safe_call_function func,
- void *udata,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top);
-DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top,
- duk_jmpbuf *old_jmpbuf_ptr);
-DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc);
+ * Limit check helpers.
+ */
+
+/* Allow headroom for calls during error augmentation (see GH-191).
+ * We allow space for 10 additional recursions, with one extra
+ * for, e.g. a print() call at the deepest level, and an extra
+ * +1 for protected call wrapping.
+ */
+#define DUK__AUGMENT_CALL_RELAX_COUNT (10 + 2)
+
+DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthread *thr) {
+ /* When augmenting an error, the effective limit is a bit higher.
+ * Check for it only if the fast path check fails.
+ */
+#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ if (thr->heap->augmenting_error) {
+ if (thr->heap->call_recursion_depth < thr->heap->call_recursion_limit + DUK__AUGMENT_CALL_RELAX_COUNT) {
+ DUK_D(DUK_DPRINT("C recursion limit reached but augmenting error and within relaxed limit"));
+ return;
+ }
+ }
+#endif
+
+ DUK_D(DUK_DPRINT("call prevented because C recursion limit reached"));
+ DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) {
+ DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
+ DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
+
+ /* This check is forcibly inlined because it's very cheap and almost
+ * always passes. The slow path is forcibly noinline.
+ */
+ if (DUK_LIKELY(thr->heap->call_recursion_depth < thr->heap->call_recursion_limit)) {
+ return;
+ }
+
+ duk__call_c_recursion_limit_check_slowpath(thr);
+}
+
+DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread *thr) {
+ /* When augmenting an error, the effective limit is a bit higher.
+ * Check for it only if the fast path check fails.
+ */
+#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ if (thr->heap->augmenting_error) {
+ if (thr->callstack_top < DUK_USE_CALLSTACK_LIMIT + DUK__AUGMENT_CALL_RELAX_COUNT) {
+ DUK_D(DUK_DPRINT("call stack limit reached but augmenting error and within relaxed limit"));
+ return;
+ }
+ }
+#endif
+
+ /* XXX: error message is a bit misleading: we reached a recursion
+ * limit which is also essentially the same as a C callstack limit
+ * (except perhaps with some relaxed threading assumptions).
+ */
+ DUK_D(DUK_DPRINT("call prevented because call stack limit reached"));
+ DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) {
+ /* This check is forcibly inlined because it's very cheap and almost
+ * always passes. The slow path is forcibly noinline.
+ */
+ if (DUK_LIKELY(thr->callstack_top < DUK_USE_CALLSTACK_LIMIT)) {
+ return;
+ }
+
+ duk__call_callstack_limit_check_slowpath(thr);
+}
/*
* Interrupt counter fixup (for development only).
@@ -59684,9 +61091,7 @@ DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_th
DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
duk_hobject *func,
duk_hobject *varenv,
- duk_idx_t idx_argbase, /* idx of first argument on stack */
- duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
- duk_context *ctx = (duk_context *) thr;
+ duk_idx_t idx_args) {
duk_hobject *arg; /* 'arguments' */
duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
duk_idx_t i_arg;
@@ -59696,30 +61101,30 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
duk_idx_t i_argbase;
duk_idx_t n_formals;
duk_idx_t idx;
+ duk_idx_t num_stack_args;
duk_bool_t need_map;
- DUK_DDD(DUK_DDDPRINT("creating arguments object for func=%!iO, varenv=%!iO, "
- "idx_argbase=%ld, num_stack_args=%ld",
- (duk_heaphdr *) func, (duk_heaphdr *) varenv,
- (long) idx_argbase, (long) num_stack_args));
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
DUK_ASSERT(varenv != NULL);
- DUK_ASSERT(idx_argbase >= 0); /* assumed to bottom relative */
- DUK_ASSERT(num_stack_args >= 0);
+
+ /* [ ... func this arg1(@idx_args) ... argN envobj ]
+ * [ arg1(@idx_args) ... argN envobj ] (for tailcalls)
+ */
need_map = 0;
- i_argbase = idx_argbase;
+ i_argbase = idx_args;
+ num_stack_args = duk_get_top(thr) - i_argbase - 1;
DUK_ASSERT(i_argbase >= 0);
+ DUK_ASSERT(num_stack_args >= 0);
- duk_push_hobject(ctx, func);
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FORMALS);
- formals = duk_get_hobject(ctx, -1);
+ duk_push_hobject(thr, func);
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS);
+ formals = duk_get_hobject(thr, -1);
if (formals) {
- n_formals = (duk_idx_t) duk_get_length(ctx, -1);
+ n_formals = (duk_idx_t) duk_get_length(thr, -1);
} else {
/* This shouldn't happen without tampering of internal
* properties: if a function accesses 'arguments', _Formals
@@ -59729,8 +61134,8 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
DUK_D(DUK_DPRINT("_Formals is undefined when creating arguments, use n_formals == 0"));
n_formals = 0;
}
- duk_remove_m2(ctx); /* leave formals on stack for later use */
- i_formals = duk_require_top_index(ctx);
+ duk_remove_m2(thr); /* leave formals on stack for later use */
+ i_formals = duk_require_top_index(thr);
DUK_ASSERT(n_formals >= 0);
DUK_ASSERT(formals != NULL || n_formals == 0);
@@ -59748,24 +61153,24 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
* - 'mappedNames' object: temporary value used during construction
*/
- arg = duk_push_object_helper(ctx,
+ arg = duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_FLAG_ARRAY_PART |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
DUK_BIDX_OBJECT_PROTOTYPE);
DUK_ASSERT(arg != NULL);
- (void) duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
-1); /* no prototype */
- (void) duk_push_object_helper(ctx,
+ (void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
-1); /* no prototype */
- i_arg = duk_get_top(ctx) - 3;
+ i_arg = duk_get_top(thr) - 3;
i_map = i_arg + 1;
i_mappednames = i_arg + 2;
@@ -59775,19 +61180,19 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
"arguments at index %ld -> %!O "
"map at index %ld -> %!O "
"mappednames at index %ld -> %!O",
- (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
- (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
- (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
+ (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
+ (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
+ (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
/*
* Init arguments properties, map, etc.
*/
- duk_push_int(ctx, num_stack_args);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
+ duk_push_int(thr, num_stack_args);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
/*
- * Init argument related properties
+ * Init argument related properties.
*/
/* step 11 */
@@ -59797,8 +61202,8 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
(long) idx, (long) i_argbase, (long) (i_argbase + idx)));
DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
- duk_dup(ctx, i_argbase + idx);
- duk_xdef_prop_index_wec(ctx, i_arg, (duk_uarridx_t) idx);
+ duk_dup(thr, i_argbase + idx);
+ duk_xdef_prop_index_wec(thr, i_arg, (duk_uarridx_t) idx);
DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
/* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
@@ -59808,12 +61213,12 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
(long) idx, (long) n_formals));
- duk_get_prop_index(ctx, i_formals, idx);
- DUK_ASSERT(duk_is_string(ctx, -1));
+ duk_get_prop_index(thr, i_formals, (duk_uarridx_t) idx);
+ DUK_ASSERT(duk_is_string(thr, -1));
- duk_dup_top(ctx); /* [ ... name name ] */
+ duk_dup_top(thr); /* [ ... name name ] */
- if (!duk_has_prop(ctx, i_mappednames)) {
+ if (!duk_has_prop(thr, i_mappednames)) {
/* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
* differs from the reference model
*/
@@ -59823,23 +61228,23 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
need_map = 1;
DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
- (const char *) duk_get_string(ctx, -1),
+ (const char *) duk_get_string(thr, -1),
(long) idx));
- duk_dup_top(ctx); /* name */
- (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) idx); /* index */
- duk_xdef_prop_wec(ctx, i_mappednames); /* out of spec, must be configurable */
+ duk_dup_top(thr); /* name */
+ (void) duk_push_uint_to_hstring(thr, (duk_uint_t) idx); /* index */
+ duk_xdef_prop_wec(thr, i_mappednames); /* out of spec, must be configurable */
DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
(long) idx,
- duk_get_string(ctx, -1)));
- duk_dup_top(ctx); /* name */
- duk_xdef_prop_index_wec(ctx, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
+ duk_get_string(thr, -1)));
+ duk_dup_top(thr); /* name */
+ duk_xdef_prop_index_wec(thr, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
} else {
/* duk_has_prop() popped the second 'name' */
}
/* [ ... name ] */
- duk_pop(ctx); /* pop 'name' */
+ duk_pop(thr); /* pop 'name' */
}
idx--;
@@ -59854,8 +61259,8 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
/* should never happen for a strict callee */
DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
- duk_dup(ctx, i_map);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
+ duk_dup(thr, i_map);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
/* The variable environment for magic variable bindings needs to be
* given by the caller and recorded in the arguments object.
@@ -59866,8 +61271,8 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
* an explicit (internal) callee property is not needed.
*/
- duk_push_hobject(ctx, varenv);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
+ duk_push_hobject(thr, varenv);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
}
/* steps 13-14 */
@@ -59887,12 +61292,12 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
- duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLER);
- duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLEE);
+ duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLER);
+ duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLEE);
} else {
DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
- duk_push_hobject(ctx, func);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
+ duk_push_hobject(thr, func);
+ duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
}
/* set exotic behavior only after we're done */
@@ -59920,47 +61325,42 @@ DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
"arguments at index %ld -> %!O "
"map at index %ld -> %!O "
"mappednames at index %ld -> %!O",
- (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
- (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
- (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
+ (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
+ (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
+ (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
- /* [ args(n) [crud] formals arguments map mappednames ] */
+ /* [ args(n) envobj formals arguments map mappednames ] */
- duk_pop_2(ctx);
- duk_remove_m2(ctx);
+ duk_pop_2(thr);
+ duk_remove_m2(thr);
- /* [ args [crud] arguments ] */
+ /* [ args(n) envobj arguments ] */
}
/* Helper for creating the arguments object and adding it to the env record
- * on top of the value stack. This helper has a very strict dependency on
- * the shape of the input stack.
+ * on top of the value stack.
*/
DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
duk_hobject *func,
duk_hobject *env,
- duk_idx_t num_stack_args) {
- duk_context *ctx = (duk_context *) thr;
-
+ duk_idx_t idx_args) {
DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
DUK_ASSERT(env != NULL);
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
/* [ ... arg1 ... argN envobj ] */
duk__create_arguments_object(thr,
func,
env,
- duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
- num_stack_args);
+ idx_args);
/* [ ... arg1 ... argN envobj argobj ] */
- duk_xdef_prop_stridx_short(ctx,
+ duk_xdef_prop_stridx_short(thr,
-2,
DUK_STRIDX_LC_ARGUMENTS,
DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
@@ -59969,117 +61369,189 @@ DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
}
/*
- * Helper for handling a "bound function" chain when a call is being made.
+ * Helpers for constructor call handling.
+ *
+ * There are two [[Construct]] operations in the specification:
+ *
+ * - E5 Section 13.2.2: for Function objects
+ * - E5 Section 15.3.4.5.2: for "bound" Function objects
*
- * Follows the bound function chain until a non-bound function is found.
- * Prepends the bound arguments to the value stack (at idx_func + 2),
- * updating 'num_stack_args' in the process. The 'this' binding is also
- * updated if necessary (at idx_func + 1). Note that for constructor calls
- * the 'this' binding is never updated by [[BoundThis]].
+ * The chain of bound functions is resolved in Section 15.3.4.5.2,
+ * with arguments "piling up" until the [[Construct]] internal
+ * method is called on the final, actual Function object. Note
+ * that the "prototype" property is looked up *only* from the
+ * final object, *before* calling the constructor.
*
- * XXX: bound function chains could be collapsed at bound function creation
- * time so that each bound function would point directly to a non-bound
- * function. This would make call time handling much easier.
+ * Since Duktape 2.2 bound functions are represented with the
+ * duk_hboundfunc internal type, and bound function chains are
+ * collapsed when a bound function is created. As a result, the
+ * direct target of a duk_hboundfunc is always non-bound and the
+ * this/argument lists have been resolved.
+ *
+ * When constructing new Array instances, an unnecessary object is
+ * created and discarded now: the standard [[Construct]] creates an
+ * object, and calls the Array constructor. The Array constructor
+ * returns an Array instance, which is used as the result value for
+ * the "new" operation; the object created before the Array constructor
+ * call is discarded.
+ *
+ * This would be easy to fix, e.g. by knowing that the Array constructor
+ * will always create a replacement object and skip creating the fallback
+ * object in that case.
+ */
+
+/* Update default instance prototype for constructor call. */
+DUK_LOCAL void duk__update_default_instance_proto(duk_hthread *thr, duk_idx_t idx_func) {
+ duk_hobject *proto;
+ duk_hobject *fallback;
+
+ DUK_ASSERT(duk_is_constructable(thr, idx_func));
+
+ duk_get_prop_stridx_short(thr, idx_func, DUK_STRIDX_PROTOTYPE);
+ proto = duk_get_hobject(thr, -1);
+ if (proto == NULL) {
+ DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
+ "-> leave standard Object prototype as fallback prototype"));
+ } else {
+ DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
+ "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
+ /* Original fallback (default instance) is untouched when
+ * resolving bound functions etc.
+ */
+ fallback = duk_known_hobject(thr, idx_func + 1);
+ DUK_ASSERT(fallback != NULL);
+ DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
+ }
+ duk_pop(thr);
+}
+
+/* Postprocess: return value special handling, error augmentation. */
+DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant) {
+ /* Use either fallback (default instance) or retval depending
+ * on retval type. Needs to be called before unwind because
+ * the default instance is read from the current (immutable)
+ * 'this' binding.
+ *
+ * For Proxy 'construct' calls the return value must be an
+ * Object (we accept object-like values like buffers and
+ * lightfuncs too). If not, TypeError.
+ */
+ if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_BUFFER |
+ DUK_TYPE_MASK_LIGHTFUNC)) {
+ DUK_DDD(DUK_DDDPRINT("replacement value"));
+ } else {
+ if (DUK_UNLIKELY(proxy_invariant != 0U)) {
+ /* Proxy 'construct' return value invariant violated. */
+ DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
+ }
+ /* XXX: direct value stack access */
+ duk_pop(thr);
+ duk_push_this(thr);
+ }
+
+#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
+ /* Augment created errors upon creation, not when they are thrown or
+ * rethrown. __FILE__ and __LINE__ are not desirable here; the call
+ * stack reflects the caller which is correct. Skip topmost, unwound
+ * activation when creating a traceback. If thr->ptr_curr_pc was !=
+ * NULL we'd need to sync the current PC so that the traceback comes
+ * out right; however it is always synced here so just assert for it.
+ */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE |
+ DUK_AUGMENT_FLAG_SKIP_ONE);
+#endif
+}
+
+/*
+ * Helper for handling a bound function when a call is being made.
+ *
+ * Assumes that bound function chains have been "collapsed" so that either
+ * the target is non-bound or there is one bound function that points to a
+ * nonbound target.
+ *
+ * Prepends the bound arguments to the value stack (at idx_func + 2).
+ * The 'this' binding is also updated if necessary (at idx_func + 1).
+ * Note that for constructor calls the 'this' binding is never updated by
+ * [[BoundThis]].
*/
DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
duk_idx_t idx_func,
- duk_idx_t *p_num_stack_args, /* may be changed by call */
duk_bool_t is_constructor_call) {
- duk_context *ctx = (duk_context *) thr;
- duk_idx_t num_stack_args;
duk_tval *tv_func;
duk_hobject *func;
- duk_uint_t sanity;
+ duk_idx_t len;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(p_num_stack_args != NULL);
/* On entry, item at idx_func is a bound, non-lightweight function,
* but we don't rely on that below.
*/
- num_stack_args = *p_num_stack_args;
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
- sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
- do {
- duk_idx_t i, len;
-
- tv_func = duk_require_tval(ctx, idx_func);
- DUK_ASSERT(tv_func != NULL);
+ tv_func = duk_require_tval(thr, idx_func);
+ DUK_ASSERT(tv_func != NULL);
- if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
- /* Lightweight function: never bound, so terminate. */
- break;
- } else if (DUK_TVAL_IS_OBJECT(tv_func)) {
- func = DUK_TVAL_GET_OBJECT(tv_func);
- if (!DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
- /* Normal non-bound function. */
- break;
- }
- } else {
- /* Function.prototype.bind() should never let this happen,
- * ugly error message is enough.
- */
- DUK_ERROR_INTERNAL(thr);
- }
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv_func) != NULL);
+ if (DUK_TVAL_IS_OBJECT(tv_func)) {
+ func = DUK_TVAL_GET_OBJECT(tv_func);
- /* XXX: this could be more compact by accessing the internal properties
- * directly as own properties (they cannot be inherited, and are not
- * externally visible).
- */
+ /* XXX: separate helper function, out of fast path? */
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
+ duk_hboundfunc *h_bound;
+ duk_tval *tv_args;
+ duk_tval *tv_gap;
- DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p, num_stack_args=%ld: %!T",
- (void *) DUK_TVAL_GET_OBJECT(tv_func), (long) num_stack_args, tv_func));
+ h_bound = (duk_hboundfunc *) func;
+ tv_args = h_bound->args;
+ len = h_bound->nargs;
+ DUK_ASSERT(len == 0 || tv_args != NULL);
- /* [ ... func this arg1 ... argN ] */
+ DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p: %!T",
+ (void *) DUK_TVAL_GET_OBJECT(tv_func), tv_func));
- if (is_constructor_call) {
- /* See: tests/ecmascript/test-spec-bound-constructor.js */
- DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
- } else {
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_THIS);
- duk_replace(ctx, idx_func + 1); /* idx_this = idx_func + 1 */
- }
+ /* [ ... func this arg1 ... argN ] */
- /* [ ... func this arg1 ... argN ] */
+ if (is_constructor_call) {
+ /* See: tests/ecmascript/test-spec-bound-constructor.js */
+ DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
+ } else {
+ /* XXX: duk_replace_tval */
+ duk_push_tval(thr, &h_bound->this_binding);
+ duk_replace(thr, idx_func + 1); /* idx_this = idx_func + 1 */
+ }
- /* XXX: duk_get_length? */
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_ARGS); /* -> [ ... func this arg1 ... argN _Args ] */
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */
- len = (duk_idx_t) duk_require_int(ctx, -1);
- duk_pop(ctx);
- for (i = 0; i < len; i++) {
- /* XXX: very slow - better to bulk allocate a gap, and copy
- * from args_array directly (we know it has a compact array
- * part, etc).
- */
+ /* [ ... func this arg1 ... argN ] */
- /* [ ... func this <some bound args> arg1 ... argN _Args ] */
- duk_get_prop_index(ctx, -1, i);
- duk_insert(ctx, idx_func + 2 + i); /* idx_args = idx_func + 2 */
- }
- num_stack_args += len; /* must be updated to work properly (e.g. creation of 'arguments') */
- duk_pop(ctx);
+ duk_require_stack(thr, len);
- /* [ ... func this <bound args> arg1 ... argN ] */
+ tv_gap = duk_reserve_gap(thr, idx_func + 2, len);
+ duk_copy_tvals_incref(thr, tv_gap, tv_args, (duk_size_t) len);
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_TARGET);
- duk_replace(ctx, idx_func); /* replace in stack */
+ /* [ ... func this <bound args> arg1 ... argN ] */
- DUK_DDD(DUK_DDDPRINT("bound function handled, num_stack_args=%ld, idx_func=%ld, curr func=%!T",
- (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func)));
- } while (--sanity > 0);
+ duk_push_tval(thr, &h_bound->target);
+ duk_replace(thr, idx_func); /* replace in stack */
- if (DUK_UNLIKELY(sanity == 0)) {
- DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
+ DUK_DDD(DUK_DDDPRINT("bound function handled, idx_func=%ld, curr func=%!T",
+ (long) idx_func, duk_get_tval(thr, idx_func)));
+ }
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
+ /* Lightweight function: never bound, so terminate. */
+ ;
+ } else {
+ /* Shouldn't happen, so ugly error is enough. */
+ DUK_ERROR_INTERNAL(thr);
}
- DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(thr, idx_func)));
#if defined(DUK_USE_ASSERTIONS)
- tv_func = duk_require_tval(ctx, idx_func);
+ tv_func = duk_require_tval(thr, idx_func);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
if (DUK_TVAL_IS_OBJECT(tv_func)) {
func = DUK_TVAL_GET_OBJECT(tv_func);
@@ -60089,12 +61561,326 @@ DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
DUK_HOBJECT_HAS_NATFUNC(func));
}
#endif
+}
- /* write back */
- *p_num_stack_args = num_stack_args;
+/*
+ * Helper for inline handling of .call(), .apply(), and .construct().
+ */
+
+DUK_LOCAL duk_bool_t duk__handle_specialfuncs_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hobject *func, duk_small_uint_t *call_flags, duk_bool_t first) {
+#if defined(DUK_USE_ASSERTIONS)
+ duk_c_function natfunc;
+#endif
+ duk_tval *tv_args;
+
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT((*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0); /* Caller. */
+
+#if defined(DUK_USE_ASSERTIONS)
+ natfunc = ((duk_hnatfunc *) func)->func;
+ DUK_ASSERT(natfunc != NULL);
+#endif
+
+ /* On every round of function resolution at least target function and
+ * 'this' binding are set. We can assume that here, and must guarantee
+ * it on exit. Value stack reserve is extended for bound function and
+ * .apply() unpacking so we don't need to extend it here when we need a
+ * few slots.
+ */
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ /* Handle native 'eval' specially. A direct eval check is only made
+ * for the first resolution attempt; e.g. a bound eval call is -not-
+ * a direct eval call.
+ */
+ if (DUK_UNLIKELY(((duk_hnatfunc *) func)->magic == 15)) {
+ /* For now no special handling except for direct eval
+ * detection.
+ */
+ DUK_ASSERT(((duk_hnatfunc *) func)->func == duk_bi_global_object_eval);
+ if (first && (*call_flags & DUK_CALL_FLAG_CALLED_AS_EVAL)) {
+ *call_flags = (*call_flags & ~DUK_CALL_FLAG_CALLED_AS_EVAL) | DUK_CALL_FLAG_DIRECT_EVAL;
+ }
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ return 1; /* stop resolving */
+ }
+
+ /* Handle special functions based on the DUK_HOBJECT_FLAG_SPECIAL_CALL
+ * flag; their magic value is used for switch-case.
+ *
+ * NOTE: duk_unpack_array_like() reserves value stack space
+ * for the result values (unlike most other value stack calls).
+ */
+ switch (((duk_hnatfunc *) func)->magic) {
+ case 0: { /* 0=Function.prototype.call() */
+ /* Value stack:
+ * idx_func + 0: Function.prototype.call() [removed]
+ * idx_func + 1: this binding for .call (target function)
+ * idx_func + 2: 1st argument to .call, desired 'this' binding
+ * idx_func + 3: 2nd argument to .call, desired 1st argument for ultimate target
+ * ...
+ *
+ * Remove idx_func + 0 to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding
+ * idx_func + 2: call arguments
+ * ...
+ */
+ DUK_ASSERT(natfunc == duk_bi_function_prototype_call);
+ duk_remove_unsafe(thr, idx_func);
+ tv_args = thr->valstack_bottom + idx_func + 2;
+ if (thr->valstack_top < tv_args) {
+ DUK_ASSERT(tv_args <= thr->valstack_end);
+ thr->valstack_top = tv_args; /* at least target function and 'this' binding present */
+ }
+ break;
+ }
+ case 1: { /* 1=Function.prototype.apply() */
+ /* Value stack:
+ * idx_func + 0: Function.prototype.apply() [removed]
+ * idx_func + 1: this binding for .apply (target function)
+ * idx_func + 2: 1st argument to .apply, desired 'this' binding
+ * idx_func + 3: 2nd argument to .apply, argArray
+ * [anything after this MUST be ignored]
+ *
+ * Remove idx_func + 0 and unpack the argArray to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding
+ * idx_func + 2: call arguments
+ * ...
+ */
+ DUK_ASSERT(natfunc == duk_bi_function_prototype_apply);
+ duk_remove_unsafe(thr, idx_func);
+ goto apply_shared;
+ }
+#if defined(DUK_USE_REFLECT_BUILTIN)
+ case 2: { /* 2=Reflect.apply() */
+ /* Value stack:
+ * idx_func + 0: Reflect.apply() [removed]
+ * idx_func + 1: this binding for .apply (ignored, usually Reflect) [removed]
+ * idx_func + 2: 1st argument to .apply, target function
+ * idx_func + 3: 2nd argument to .apply, desired 'this' binding
+ * idx_func + 4: 3rd argument to .apply, argArray
+ * [anything after this MUST be ignored]
+ *
+ * Remove idx_func + 0 and idx_func + 1, and unpack the argArray to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding
+ * idx_func + 2: call arguments
+ * ...
+ */
+ DUK_ASSERT(natfunc == duk_bi_reflect_apply);
+ duk_remove_n_unsafe(thr, idx_func, 2);
+ goto apply_shared;
+ }
+ case 3: { /* 3=Reflect.construct() */
+ /* Value stack:
+ * idx_func + 0: Reflect.construct() [removed]
+ * idx_func + 1: this binding for .construct (ignored, usually Reflect) [removed]
+ * idx_func + 2: 1st argument to .construct, target function
+ * idx_func + 3: 2nd argument to .construct, argArray
+ * idx_func + 4: 3rd argument to .construct, newTarget
+ * [anything after this MUST be ignored]
+ *
+ * Remove idx_func + 0 and idx_func + 1, unpack the argArray,
+ * and insert default instance (prototype not yet updated), to get:
+ * idx_func + 0: target function
+ * idx_func + 1: this binding (default instance)
+ * idx_func + 2: constructor call arguments
+ * ...
+ *
+ * Call flags must be updated to reflect the fact that we're
+ * now dealing with a constructor call, and e.g. the 'this'
+ * binding cannot be overwritten if the target is bound.
+ *
+ * newTarget is checked but not yet passed onwards.
+ */
+
+ duk_idx_t top;
+
+ DUK_ASSERT(natfunc == duk_bi_reflect_construct);
+ *call_flags |= DUK_CALL_FLAG_CONSTRUCT;
+ duk_remove_n_unsafe(thr, idx_func, 2);
+ top = duk_get_top(thr);
+ if (!duk_is_constructable(thr, idx_func)) {
+ /* Target constructability must be checked before
+ * unpacking argArray (which may cause side effects).
+ * Just return; caller will throw the error.
+ */
+ duk_set_top_unsafe(thr, idx_func + 2); /* satisfy asserts */
+ break;
+ }
+ duk_push_object(thr);
+ duk_insert(thr, idx_func + 1); /* default instance */
+
+ /* [ ... func default_instance argArray newTarget? ] */
+
+ top = duk_get_top(thr);
+ if (top < idx_func + 3) {
+ /* argArray is a mandatory argument for Reflect.construct(). */
+ DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ }
+ if (top > idx_func + 3) {
+ if (!duk_strict_equals(thr, idx_func, idx_func + 3)) {
+ /* XXX: [[Construct]] newTarget currently unsupported */
+ DUK_ERROR_UNSUPPORTED(thr);
+ }
+ duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */
+ }
+ DUK_ASSERT(duk_get_top(thr) == idx_func + 3);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
+ (void) duk_unpack_array_like(thr, idx_func + 2); /* XXX: should also remove target to be symmetric with duk_pack()? */
+ duk_remove(thr, idx_func + 2);
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ break;
+ }
+#endif /* DUK_USE_REFLECT_BUILTIN */
+ default: {
+ DUK_ASSERT(0);
+ DUK_UNREACHABLE();
+ }
+ }
+
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ return 0; /* keep resolving */
+
+ apply_shared:
+ tv_args = thr->valstack_bottom + idx_func + 2;
+ if (thr->valstack_top <= tv_args) {
+ DUK_ASSERT(tv_args <= thr->valstack_end);
+ thr->valstack_top = tv_args; /* at least target func and 'this' binding present */
+ /* No need to check for argArray. */
+ } else {
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 3); /* idx_func + 2 covered above */
+ if (thr->valstack_top > tv_args + 1) {
+ duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */
+ }
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
+ if (!duk_is_callable(thr, idx_func)) {
+ /* Avoid unpack side effects if the target isn't callable.
+ * Calling code will throw the actual error.
+ */
+ } else {
+ (void) duk_unpack_array_like(thr, idx_func + 2);
+ duk_remove(thr, idx_func + 2);
+ }
+ }
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+ return 0; /* keep resolving */
}
/*
+ * Helper for Proxy handling.
+ */
+
+#if defined(DUK_USE_ES6_PROXY)
+DUK_LOCAL void duk__handle_proxy_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hproxy *h_proxy, duk_small_uint_t *call_flags) {
+ duk_bool_t rc;
+
+ /* Value stack:
+ * idx_func + 0: Proxy object
+ * idx_func + 1: this binding for call
+ * idx_func + 2: 1st argument for call
+ * idx_func + 3: 2nd argument for call
+ * ...
+ *
+ * If Proxy doesn't have a trap for the call ('apply' or 'construct'),
+ * replace Proxy object with target object.
+ *
+ * If we're dealing with a normal call and the Proxy has an 'apply'
+ * trap, manipulate value stack to:
+ *
+ * idx_func + 0: trap
+ * idx_func + 1: Proxy's handler
+ * idx_func + 2: Proxy's target
+ * idx_func + 3: this binding for call (from idx_func + 1)
+ * idx_func + 4: call arguments packed to an array
+ *
+ * If we're dealing with a constructor call and the Proxy has a
+ * 'construct' trap, manipulate value stack to:
+ *
+ * idx_func + 0: trap
+ * idx_func + 1: Proxy's handler
+ * idx_func + 2: Proxy's target
+ * idx_func + 3: call arguments packed to an array
+ * idx_func + 4: newTarget == Proxy object here
+ *
+ * As we don't yet have proper newTarget support, the newTarget at
+ * idx_func + 3 is just the original constructor being called, i.e.
+ * the Proxy object (not the target). Note that the default instance
+ * (original 'this' binding) is dropped and ignored.
+ */
+
+ duk_push_hobject(thr, h_proxy->handler);
+ rc = duk_get_prop_stridx_short(thr, -1, (*call_flags & DUK_CALL_FLAG_CONSTRUCT) ? DUK_STRIDX_CONSTRUCT : DUK_STRIDX_APPLY);
+ if (rc == 0) {
+ /* Not found, continue to target. If this is a construct
+ * call, update default instance prototype using the Proxy,
+ * not the target.
+ */
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
+ *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
+ duk__update_default_instance_proto(thr, idx_func);
+ }
+ }
+ duk_pop_2(thr);
+ duk_push_hobject(thr, h_proxy->target);
+ duk_replace(thr, idx_func);
+ return;
+ }
+
+ /* Here we must be careful not to replace idx_func while
+ * h_proxy is still needed, otherwise h_proxy may become
+ * dangling. This could be improved e.g. using a
+ * duk_pack_slice() with a freeform slice.
+ */
+
+ /* Here:
+ * idx_func + 0: Proxy object
+ * idx_func + 1: this binding for call
+ * idx_func + 2: 1st argument for call
+ * idx_func + 3: 2nd argument for call
+ * ...
+ * idx_func + N: handler
+ * idx_func + N + 1: trap
+ */
+
+ duk_insert(thr, idx_func + 1);
+ duk_insert(thr, idx_func + 2);
+ duk_push_hobject(thr, h_proxy->target);
+ duk_insert(thr, idx_func + 3);
+ duk_pack(thr, duk_get_top(thr) - (idx_func + 5));
+
+ /* Here:
+ * idx_func + 0: Proxy object
+ * idx_func + 1: trap
+ * idx_func + 2: Proxy's handler
+ * idx_func + 3: Proxy's target
+ * idx_func + 4: this binding for call
+ * idx_func + 5: arguments array
+ */
+ DUK_ASSERT(duk_get_top(thr) == idx_func + 6);
+
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ *call_flags |= DUK_CALL_FLAG_CONSTRUCT_PROXY; /* Enable 'construct' trap return invariant check. */
+ *call_flags &= ~(DUK_CALL_FLAG_CONSTRUCT); /* Resume as non-constructor call to the trap. */
+
+ /* 'apply' args: target, thisArg, argArray
+ * 'construct' args: target, argArray, newTarget
+ */
+ duk_remove(thr, idx_func + 4);
+ duk_push_hobject(thr, (duk_hobject *) h_proxy);
+ }
+
+ /* Finalize value stack layout by removing Proxy reference. */
+ duk_remove(thr, idx_func);
+ h_proxy = NULL; /* invalidated */
+ DUK_ASSERT(duk_get_top(thr) == idx_func + 5);
+}
+#endif /* DUK_USE_ES6_PROXY */
+
+/*
* Helper for setting up var_env and lex_env of an activation,
* assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
*/
@@ -60149,7 +61935,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
DUK_ASSERT(thr->callstack_top > 0);
act_callee = thr->callstack_curr;
DUK_ASSERT(act_callee != NULL);
- act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
+ act_caller = (thr->callstack_top >= 2 ? act_callee->parent : NULL);
/* XXX: check .caller writability? */
@@ -60166,7 +61952,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* because 'func' has been resolved to a non-bound function.
*/
- if (act_caller) {
+ if (act_caller != NULL) {
/* act_caller->func may be NULL in some finalization cases,
* just treat like we don't know the caller.
*/
@@ -60187,7 +61973,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* is transferred to prev_caller.
*/
- if (act_caller) {
+ if (act_caller != NULL) {
DUK_ASSERT(act_caller->func != NULL);
DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
DUK_TVAL_INCREF(thr, tv_caller);
@@ -60198,7 +61984,7 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
/* 'caller' must only take on 'null' or function value */
DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
DUK_ASSERT(act_callee->prev_caller == NULL);
- if (act_caller && act_caller->func) {
+ if (act_caller != NULL && act_caller->func) {
/* Tolerate act_caller->func == NULL which happens in
* some finalization cases; treat like unknown caller.
*/
@@ -60213,15 +61999,21 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
/*
- * Determine the effective 'this' binding and coerce the current value
- * on the valstack to the effective one (in-place, at idx_this).
+ * Shared helpers for resolving the final, non-bound target function of the
+ * call and the effective 'this' binding. Resolves bound functions and
+ * applies .call(), .apply(), and .construct() inline.
+ *
+ * Proxy traps are also handled inline so that if the target is a Proxy with
+ * a 'call' or 'construct' trap, the trap handler is called with a modified
+ * argument list.
*
- * The current this value in the valstack (at idx_this) represents either:
- * - the caller's requested 'this' binding; or
- * - a 'this' binding accumulated from the bound function chain
+ * Once the bound function / .call() / .apply() / .construct() sequence has
+ * been resolved, the value at idx_func + 1 may need coercion described in
+ * E5 Section 10.4.3.
*
- * The final 'this' binding for the target function may still be
- * different, and is determined as described in E5 Section 10.4.3.
+ * A call that begins as a non-constructor call may be converted into a
+ * constructor call during the resolution process if Reflect.construct()
+ * is invoked. This is handled by updating the caller's call_flags.
*
* For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
* that the caller has provided the correct 'this' binding explicitly
@@ -60231,24 +62023,14 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* - direct eval: this=copy from eval() caller's this binding
* - other eval: this=global object
*
- * Note: this function may cause a recursive function call with arbitrary
+ * The 'this' coercion may cause a recursive function call with arbitrary
* side effects, because ToObject() may be called.
*/
-DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
- duk_hobject *func,
- duk_idx_t idx_this) {
- duk_context *ctx = (duk_context *) thr;
+DUK_LOCAL DUK_INLINE void duk__coerce_nonstrict_this_binding(duk_hthread *thr, duk_idx_t idx_this) {
duk_tval *tv_this;
duk_hobject *obj_global;
- if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
- /* Lightfuncs are always considered strict. */
- DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
- return;
- }
-
- /* XXX: byte offset */
tv_this = thr->valstack_bottom + idx_this;
switch (DUK_TVAL_GET_TAG(tv_this)) {
case DUK_TAG_OBJECT:
@@ -60275,144 +62057,238 @@ DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
default:
/* Plain buffers and lightfuncs are object coerced. Lightfuncs
* very rarely come here however, because the call target would
- * need to be a strict non-lightfunc (lightfuncs are considered
+ * need to be a non-strict non-lightfunc (lightfuncs are considered
* strict) with an explicit lightfunc 'this' binding.
*/
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
- duk_to_object(ctx, idx_this); /* may have side effects */
+ duk_to_object(thr, idx_this); /* may have side effects */
break;
}
}
-/*
- * Shared helper for non-bound func lookup.
- *
- * Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
- */
+DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__resolve_target_fastpath_check(duk_hthread *thr, duk_idx_t idx_func, duk_hobject **out_func, duk_small_uint_t call_flags) {
+#if defined(DUK_USE_PREFER_SIZE)
+ DUK_UNREF(thr);
+ DUK_UNREF(idx_func);
+ DUK_UNREF(out_func);
+ DUK_UNREF(call_flags);
+#else /* DUK_USE_PREFER_SIZE */
+ duk_tval *tv_func;
+ duk_hobject *func;
-DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
- duk_idx_t idx_func,
- duk_idx_t *out_num_stack_args,
- duk_tval **out_tv_func,
- duk_small_uint_t call_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+ if (DUK_UNLIKELY(call_flags & DUK_CALL_FLAG_CONSTRUCT)) {
+ return 0;
+ }
+
+ tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
+ DUK_ASSERT(tv_func != NULL);
+
+ if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv_func))) {
+ func = DUK_TVAL_GET_OBJECT(tv_func);
+ if (DUK_HOBJECT_IS_CALLABLE(func) &&
+ !DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
+ !DUK_HOBJECT_HAS_SPECIAL_CALL(func)) {
+ *out_func = func;
+
+ if (DUK_HOBJECT_HAS_STRICT(func)) {
+ /* Strict function: no 'this' coercion. */
+ return 1;
+ }
+
+ duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
+ return 1;
+ }
+ } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
+ *out_func = NULL;
+
+ /* Lightfuncs are considered strict, so 'this' binding is
+ * used as is. They're never bound, always constructable,
+ * and never special functions.
+ */
+ return 1;
+ }
+#endif /* DUK_USE_PREFER_SIZE */
+ return 0; /* let slow path deal with it */
+}
+
+DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_small_uint_t *call_flags) {
duk_tval *tv_func;
duk_hobject *func;
+ duk_bool_t first;
- for (;;) {
- /* Use loop to minimize code size of relookup after bound function case */
- tv_func = DUK_GET_TVAL_POSIDX(ctx, idx_func);
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ for (first = 1;; first = 0) {
+ DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
+
+ tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
DUK_ASSERT(tv_func != NULL);
if (DUK_TVAL_IS_OBJECT(tv_func)) {
func = DUK_TVAL_GET_OBJECT(tv_func);
- if (!DUK_HOBJECT_IS_CALLABLE(func)) {
- goto not_callable_error;
+
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ if (DUK_UNLIKELY(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func))) {
+ goto not_constructable;
+ }
+ } else {
+ if (DUK_UNLIKELY(!DUK_HOBJECT_IS_CALLABLE(func))) {
+ goto not_callable;
+ }
}
+
+ if (DUK_LIKELY(!DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
+ !DUK_HOBJECT_HAS_SPECIAL_CALL(func) &&
+ !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func))) {
+ /* Common case, so test for using a single bitfield test.
+ * Break out to handle this coercion etc.
+ */
+ break;
+ }
+
+ /* XXX: could set specialcall for boundfuncs too, simplify check above */
+
if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
- duk__handle_bound_chain_for_call(thr, idx_func, out_num_stack_args, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
+ DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_CALL(func));
+ DUK_ASSERT(!DUK_HOBJECT_IS_NATFUNC(func));
- /* The final object may be a normal function or a lightfunc.
- * We need to re-lookup tv_func because it may have changed
- * (also value stack may have been resized). Loop again to
- * do that; we're guaranteed not to come here again.
+ /* Callable/constructable flags are the same
+ * for the bound function and its target, so
+ * we don't need to check them here, we can
+ * check them from the target only.
*/
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(ctx, idx_func)) ||
- DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(ctx, idx_func)));
- continue;
+ duk__handle_bound_chain_for_call(thr, idx_func, *call_flags & DUK_CALL_FLAG_CONSTRUCT);
+
+ DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(thr, idx_func)) ||
+ DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(thr, idx_func)));
+ } else {
+ DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_CALL(func));
+
+#if defined(DUK_USE_ES6_PROXY)
+ if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func)) {
+ /* If no trap, resume processing from Proxy trap.
+ * If trap exists, helper converts call into a trap
+ * call; this may change a constructor call into a
+ * normal (non-constructor) trap call. We must
+ * continue processing even when a trap is found as
+ * the trap may be bound.
+ */
+ duk__handle_proxy_for_call(thr, idx_func, (duk_hproxy *) func, call_flags);
+ }
+ else
+#endif
+ {
+ DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
+ DUK_ASSERT(DUK_HOBJECT_HAS_CALLABLE(func));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func));
+ /* Constructable check already done above. */
+
+ if (duk__handle_specialfuncs_for_call(thr, idx_func, func, call_flags, first) != 0) {
+ /* Encountered native eval call, normal call
+ * context. Break out, handle this coercion etc.
+ */
+ break;
+ }
+ }
}
+ /* Retry loop. */
} else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
+ /* Lightfuncs are:
+ * - Always strict, so no 'this' coercion.
+ * - Always callable.
+ * - Always constructable.
+ * - Never specialfuncs.
+ */
func = NULL;
+ goto finished;
} else {
- goto not_callable_error;
+ goto not_callable;
}
- break;
}
- DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_func) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_func))) ||
- DUK_TVAL_IS_LIGHTFUNC(tv_func));
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
- DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
- DUK_HOBJECT_IS_NATFUNC(func)));
-
- *out_tv_func = tv_func;
- return func;
-
- not_callable_error:
- DUK_ASSERT(tv_func != NULL);
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
-#else
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func));
-#endif
- DUK_UNREACHABLE();
- return NULL; /* never executed */
-}
-
-/*
- * Value stack resize and stack top adjustment helper.
- *
- * XXX: This should all be merged to duk_valstack_resize_raw().
- */
+ DUK_ASSERT(func != NULL);
-DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_idx_t idx_args,
- duk_idx_t nregs,
- duk_idx_t nargs,
- duk_hobject *func) {
- duk_context *ctx = (duk_context *) thr;
- duk_size_t vs_min_size;
- duk_bool_t adjusted_top = 0;
-
- vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- idx_args; /* bottom of new func */
-
- if (nregs >= 0) {
- DUK_ASSERT(nargs >= 0);
- DUK_ASSERT(nregs >= nargs);
- vs_min_size += nregs;
- } else {
- /* 'func' wants stack "as is" */
- vs_min_size += num_stack_args; /* num entries of new func at entry */
+ if (!DUK_HOBJECT_HAS_STRICT(func)) {
+ /* Non-strict target needs 'this' coercion.
+ * This has potential side effects invalidating
+ * 'tv_func'.
+ */
+ duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
}
- if (func == NULL || DUK_HOBJECT_IS_NATFUNC(func)) {
- vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
+ if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
+ *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
+ duk__update_default_instance_proto(thr, idx_func);
+ }
}
- vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
- /* XXX: We can't resize the value stack to a size smaller than the
- * current top, so the order of the resize and adjusting the stack
- * top depends on the current vs. final size of the value stack.
- * The operations could be combined to avoid this, but the proper
- * fix is to only grow the value stack on a function call, and only
- * shrink it (without throwing if the shrink fails) on function
- * return.
- */
+ finished:
+
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_tval *tv_tmp;
- if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
- DUK_DDD(DUK_DDDPRINT(("final size smaller, set top before resize")));
+ tv_tmp = duk_get_tval(thr, idx_func);
+ DUK_ASSERT(tv_tmp != NULL);
- DUK_ASSERT(nregs >= 0); /* can't happen when keeping current stack size */
- duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
- duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
- adjusted_top = 1;
+ DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_tmp) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_tmp))) ||
+ DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
+ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
+ DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
+ DUK_HOBJECT_IS_NATFUNC(func)));
+ DUK_ASSERT(func == NULL || (DUK_HOBJECT_HAS_CONSTRUCTABLE(func) ||
+ (*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0));
}
+#endif
- (void) duk_valstack_resize_raw((duk_context *) thr,
- vs_min_size,
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ return func;
- if (!adjusted_top) {
- if (nregs >= 0) {
- DUK_ASSERT(nregs >= nargs);
- duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
- duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
+ not_callable:
+ DUK_ASSERT(tv_func != NULL);
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ /* GETPROPC delayed error handling: when target is not callable,
+ * GETPROPC replaces idx_func+0 with an Error (non-callable) with
+ * a hidden Symbol to signify it's to be thrown as is here. The
+ * hidden Symbol is only checked as an own property, not inherited
+ * (which would be dangerous).
+ */
+ if (DUK_TVAL_IS_OBJECT(tv_func)) {
+ if (duk_hobject_find_existing_entry_tval_ptr(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_HTHREAD_STRING_INT_TARGET(thr)) != NULL) {
+ duk_push_tval(thr, tv_func);
+ (void) duk_throw(thr);
}
}
+#endif
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_PARANOID_ERRORS)
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_get_type_name(thr, idx_func));
+#else
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(thr, tv_func));
+#endif
+#else
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
+#endif
+ DUK_UNREACHABLE();
+ return NULL; /* never executed */
+
+ not_constructable:
+ /* For now GETPROPC delayed error not needed for constructor calls. */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+#if defined(DUK_USE_PARANOID_ERRORS)
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(thr, idx_func));
+#else
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_tval_readable(thr, tv_func));
+#endif
+#else
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
+#endif
+ DUK_UNREACHABLE();
+ return NULL; /* never executed */
}
/*
@@ -60426,7 +62302,6 @@ DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
*/
DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) {
- duk_context *ctx = (duk_context *) thr;
duk_idx_t idx_rcbase;
DUK_ASSERT(thr != NULL);
@@ -60434,540 +62309,395 @@ DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_re
DUK_ASSERT(num_stack_rets >= 0);
DUK_ASSERT(num_actual_rets >= 0);
- idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
+ idx_rcbase = duk_get_top(thr) - num_actual_rets; /* base of known return values */
+ if (DUK_UNLIKELY(idx_rcbase < 0)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
+ }
DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
"num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
- (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
+ (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(thr),
(long) idx_retbase, (long) idx_rcbase));
DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
- /* Ensure space for final configuration (idx_retbase + num_stack_rets)
- * and intermediate configurations.
+ /* Space for num_stack_rets was reserved before the safe call.
+ * Because value stack reserve cannot shrink except in call returns,
+ * the reserve is still in place. Adjust valstack, carefully
+ * ensuring we don't overstep the reserve.
*/
- duk_require_stack_top(ctx,
- (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
- num_stack_rets);
-
- /* Chop extra retvals away / extend with undefined. */
- duk_set_top(ctx, idx_rcbase + num_stack_rets);
- if (idx_rcbase >= idx_retbase) {
+ /* Match idx_rcbase with idx_retbase so that the return values
+ * start at the correct index.
+ */
+ if (idx_rcbase > idx_retbase) {
duk_idx_t count = idx_rcbase - idx_retbase;
- duk_idx_t i;
DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
"(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
- /* nuke values at idx_retbase to get the first retval (initially
- * at idx_rcbase) to idx_retbase
+ /* Remove values between irc_rcbase (start of intended return
+ * values) and idx_retbase to lower return values to idx_retbase.
*/
-
- DUK_ASSERT(count >= 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block remove primitive */
- duk_remove(ctx, idx_retbase);
- }
+ DUK_ASSERT(count > 0);
+ duk_remove_n(thr, idx_retbase, count); /* may be NORZ */
} else {
duk_idx_t count = idx_retbase - idx_rcbase;
- duk_idx_t i;
DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
"(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
- /* insert 'undefined' values at idx_rcbase to get the
- * return values to idx_retbase
+ /* Insert 'undefined' at idx_rcbase (start of intended return
+ * values) to lift return values to idx_retbase.
*/
-
- DUK_ASSERT(count > 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block insert primitive */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_rcbase);
- }
+ DUK_ASSERT(count >= 0);
+ DUK_ASSERT(thr->valstack_end - thr->valstack_top >= count); /* reserve cannot shrink */
+ duk_insert_undefined_n(thr, idx_rcbase, count);
}
-}
-/*
- * Misc shared helpers.
- */
-
-/* Get valstack index for the func argument or throw if insane stack. */
-DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args) {
- duk_size_t off_stack_top;
- duk_size_t off_stack_args;
- duk_size_t off_stack_all;
- duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
-
- /* Argument validation and func/args offset. */
- off_stack_top = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack_bottom);
- off_stack_args = (duk_size_t) ((duk_size_t) num_stack_args * sizeof(duk_tval));
- off_stack_all = off_stack_args + 2 * sizeof(duk_tval);
- if (DUK_UNLIKELY(off_stack_all > off_stack_top)) {
- /* Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
- */
- DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return 0;
- }
- idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
- return idx_func;
+ /* Chop extra retvals away / extend with undefined. */
+ duk_set_top_unsafe(thr, idx_retbase + num_stack_rets);
}
/*
- * duk_handle_call_protected() and duk_handle_call_unprotected():
- * call into a Duktape/C or an Ecmascript function from any state.
- *
- * Input stack (thr):
- *
- * [ func this arg1 ... argN ]
- *
- * Output stack (thr):
- *
- * [ retval ] (DUK_EXEC_SUCCESS)
- * [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
- *
- * Even when executing a protected call an error may be thrown in rare cases
- * such as an insane num_stack_args argument. If there is no catchpoint for
- * such errors, the fatal error handler is called.
- *
- * The error handling path should be error free, even for out-of-memory
- * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
- * yet the case, see XXX notes below.)
+ * Activation setup for tailcalls and non-tailcalls.
*/
-DUK_INTERNAL duk_int_t duk_handle_call_protected(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_context *ctx;
- duk_size_t entry_valstack_bottom_index;
- duk_size_t entry_valstack_end;
- duk_size_t entry_callstack_top;
- duk_size_t entry_catchstack_top;
- duk_int_t entry_call_recursion_depth;
- duk_hthread *entry_curr_thread;
- duk_uint_fast8_t entry_thread_state;
- duk_instr_t **entry_ptr_curr_pc;
- duk_jmpbuf *old_jmpbuf_ptr = NULL;
- duk_jmpbuf our_jmpbuf;
- duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+#if defined(DUK_USE_TAILCALL)
+DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func,
+ duk_hobject *func,
+ duk_size_t entry_valstack_bottom_byteoff,
+ duk_size_t entry_valstack_end_byteoff,
+ duk_idx_t *out_nargs,
+ duk_idx_t *out_nregs,
+ duk_size_t *out_vs_min_bytes,
+ duk_activation **out_act) {
+ duk_activation *act;
+ duk_tval *tv1, *tv2;
+ duk_idx_t idx_args;
+ duk_small_uint_t flags1, flags2;
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ duk_activation *prev_pause_act;
+#endif
- /* XXX: Multiple tv_func lookups are now avoided by making a local
- * copy of tv_func. Another approach would be to compute an offset
- * for tv_func from valstack bottom and recomputing the tv_func
- * pointer quickly as valstack + offset instead of calling duk_get_tval().
- */
+ DUK_UNREF(entry_valstack_end_byteoff);
- ctx = (duk_context *) thr;
- DUK_UNREF(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(num_stack_args >= 0);
- /* XXX: currently NULL allocations are not supported; remove if later allowed */
- DUK_ASSERT(thr->valstack != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->catchstack != NULL);
+ /* Tailcall cannot be flagged to resume calls, and a
+ * previous frame must exist.
+ */
+ DUK_ASSERT(thr->callstack_top >= 1);
- /* Argument validation and func/args offset. */
- idx_func = duk__get_idx_func(thr, num_stack_args);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ *out_act = act;
- /* Preliminaries, required by setjmp() handler. Must be careful not
- * to throw an unintended error here.
+ if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) {
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by target not being ecma function"));
+ return 0;
+ }
+ if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENT_YIELD"));
+ return 0;
+ }
+ /* Tailcall is only allowed if current and candidate
+ * function have identical return value handling. There
+ * are three possible return value handling cases:
+ * 1. Normal function call, no special return value handling.
+ * 2. Constructor call, return value replacement object check.
+ * 3. Proxy 'construct' trap call, return value invariant check.
*/
-
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
-#if defined(DUK_USE_PREFER_SIZE)
- entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
-#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- entry_valstack_end = thr->valstack_size;
+ flags1 = (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT) ? 1 : 0)
+#if defined(DUK_USE_ES6_PROXY)
+ | (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) ? 2 : 0)
#endif
- entry_callstack_top = thr->callstack_top;
- entry_catchstack_top = thr->catchstack_top;
- entry_call_recursion_depth = thr->heap->call_recursion_depth;
- entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
- entry_thread_state = thr->state;
- entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
+ ;
+ flags2 = (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) ? 1 : 0)
+#if defined(DUK_USE_ES6_PROXY)
+ | (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) ? 2 : 0);
+#endif
+ ;
+ if (flags1 != flags2) {
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by incompatible return value handling"));
+ return 0;
+ }
+ DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT) && (call_flags & DUK_CALL_FLAG_CONSTRUCT)) ||
+ (!(act->flags & DUK_ACT_FLAG_CONSTRUCT) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT)));
+ DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)) ||
+ (!(act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)));
+ if (DUK_HOBJECT_HAS_NOTAIL(func)) {
+ /* See: test-bug-tailcall-preventyield-assert.c. */
+ DUK_DDD(DUK_DDDPRINT("tail call prevented by function having a notail flag"));
+ return 0;
+ }
- DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
- "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
- "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
- "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
- "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
- (void *) thr,
- (long) num_stack_args,
- (unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
- (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
- (long) duk_get_top(ctx),
- (long) idx_func,
- (long) (idx_func + 2),
- (long) thr->heap->call_recursion_depth,
- (long) thr->heap->call_recursion_limit,
- (long) entry_valstack_bottom_index,
- (long) entry_callstack_top,
- (long) entry_catchstack_top,
- (long) entry_call_recursion_depth,
- (void *) entry_curr_thread,
- (long) entry_thread_state));
+ /*
+ * Tailcall handling
+ *
+ * Although the callstack entry is reused, we need to explicitly unwind
+ * the current activation (or simulate an unwind). In particular, the
+ * current activation must be closed, otherwise something like
+ * test-bug-reduce-judofyr.js results. Also catchers need to be unwound
+ * because there may be non-error-catching label entries in valid tail calls.
+ *
+ * Special attention is needed for debugger and pause behavior when
+ * reusing an activation.
+ * - Disable StepOut processing for the activation unwind because
+ * we reuse the activation, see:
+ * https://github.com/svaarala/duktape/issues/1684.
+ * - Disable line change pause flag permanently (if set) because
+ * it would no longer be relevant, see:
+ * https://github.com/svaarala/duktape/issues/1726.
+ * - Check for function entry (e.g. StepInto) pause flag here, because
+ * the executor pause check won't trigger due to shared activation, see:
+ * https://github.com/svaarala/duktape/issues/1726.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
+ (long) (thr->callstack_top - 1)));
- old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
- thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
+ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
+ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ DUK_ASSERT(call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA);
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- try {
-#else
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
- if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
+ /* Unwind the topmost callstack entry before reusing it. This
+ * also unwinds the catchers related to the topmost entry.
+ */
+ DUK_ASSERT(thr->callstack_top > 0);
+ DUK_ASSERT(thr->callstack_curr != NULL);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ prev_pause_act = thr->heap->dbg_pause_act;
+ thr->heap->dbg_pause_act = NULL;
+ thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE;
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)"));
+ duk_debug_set_paused(thr->heap);
+ }
#endif
- /* Call handling and success path. Success path exit cleans
- * up almost all state.
- */
- duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
+ duk_hthread_activation_unwind_reuse_norz(thr);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ thr->heap->dbg_pause_act = prev_pause_act;
+#endif
+ DUK_ASSERT(act == thr->callstack_curr);
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+ /* XXX: We could restore the caller's value stack reserve
+ * here, as if we did an actual unwind-and-call. Without
+ * the restoration, value stack reserve may remain higher
+ * than would otherwise be possible until we return to a
+ * non-tailcall.
+ */
- return DUK_EXEC_SUCCESS;
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- } catch (duk_internal_exception &exc) {
-#else
- } else {
+ /* Then reuse the unwound activation. */
+ act->cat = NULL;
+ act->var_env = NULL;
+ act->lex_env = NULL;
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
+ act->func = func; /* don't want an intermediate exposed state with func == NULL */
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+ act->prev_caller = NULL;
#endif
- /* Error; error value is in heap->lj.value1. */
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- DUK_UNREF(exc);
+ /* don't want an intermediate exposed state with invalid pc */
+ act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ act->prev_line = 0;
#endif
+ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
+ DUK_HOBJECT_INCREF(thr, func);
- duk__handle_call_error(thr,
- entry_valstack_bottom_index,
- entry_valstack_end,
- entry_catchstack_top,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc,
- idx_func,
- old_jmpbuf_ptr);
-
- return DUK_EXEC_ERROR;
+ act->flags = DUK_ACT_FLAG_TAILCALLED;
+ if (DUK_HOBJECT_HAS_STRICT(func)) {
+ act->flags |= DUK_ACT_FLAG_STRICT;
}
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- catch (std::exception &exc) {
- const char *what = exc.what();
- if (!what) {
- what = "unknown";
- }
- DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
- DUK_UNREF(exc);
- duk__handle_call_error(thr,
- entry_valstack_bottom_index,
- entry_valstack_end,
- entry_catchstack_top,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc,
- idx_func,
- old_jmpbuf_ptr);
-
- return DUK_EXEC_ERROR;
- }
- } catch (...) {
- DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
- DUK_UNREF(exc);
- duk__handle_call_error(thr,
- entry_valstack_bottom_index,
- entry_valstack_end,
- entry_catchstack_top,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc,
- idx_func,
- old_jmpbuf_ptr);
-
- return DUK_EXEC_ERROR;
- }
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ act->flags |= DUK_ACT_FLAG_CONSTRUCT;
+ }
+#if defined(DUK_USE_ES6_PROXY)
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
+ act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
}
#endif
-}
-
-DUK_INTERNAL void duk_handle_call_unprotected(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
-
- /* Argument validation and func/args offset. */
- idx_func = duk__get_idx_func(thr, num_stack_args);
-
- duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
-}
-
-DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags,
- duk_idx_t idx_func) {
- duk_context *ctx;
- duk_size_t entry_valstack_bottom_index;
- duk_size_t entry_valstack_end;
- duk_size_t entry_callstack_top;
- duk_size_t entry_catchstack_top;
- duk_int_t entry_call_recursion_depth;
- duk_hthread *entry_curr_thread;
- duk_uint_fast8_t entry_thread_state;
- duk_instr_t **entry_ptr_curr_pc;
- 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") */
- duk_hobject *func; /* 'func' on stack (borrowed reference) */
- duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
- duk_tval tv_func_copy; /* to avoid relookups */
- duk_activation *act;
- duk_hobject *env;
- duk_ret_t rc;
-
- ctx = (duk_context *) thr;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(num_stack_args >= 0);
- /* XXX: currently NULL allocations are not supported; remove if later allowed */
- DUK_ASSERT(thr->valstack != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->catchstack != NULL);
-
- DUK_DD(DUK_DDPRINT("duk__handle_call_inner: num_stack_args=%ld, call_flags=0x%08lx, top=%ld",
- (long) num_stack_args, (long) call_flags, (long) duk_get_top(ctx)));
-
- /*
- * Store entry state.
- */
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
-#if defined(DUK_USE_PREFER_SIZE)
- entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
-#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- entry_valstack_end = thr->valstack_size;
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
+ DUK_ASSERT(act->var_env == NULL);
+ DUK_ASSERT(act->lex_env == NULL);
+ act->bottom_byteoff = entry_valstack_bottom_byteoff; /* tail call -> reuse current "frame" */
+#if 0
+ /* Topmost activation retval_byteoff is considered garbage, no need to init. */
+ act->retval_byteoff = 0;
#endif
- entry_callstack_top = thr->callstack_top;
- entry_catchstack_top = thr->catchstack_top;
- entry_call_recursion_depth = thr->heap->call_recursion_depth;
- entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
- entry_thread_state = thr->state;
- entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
-
- /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
- * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
- * activation when side effects occur.
+ /* Filled in when final reserve is known, dummy value doesn't matter
+ * even in error unwind because reserve_byteoff is only used when
+ * returning to -this- activation.
*/
- duk_hthread_sync_and_null_currpc(thr);
-
- DUK_DD(DUK_DDPRINT("duk__handle_call_inner: thr=%p, num_stack_args=%ld, "
- "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
- "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
- "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
- "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
- (void *) thr,
- (long) num_stack_args,
- (unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
- (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
- (long) duk_get_top(ctx),
- (long) idx_func,
- (long) (idx_func + 2),
- (long) thr->heap->call_recursion_depth,
- (long) thr->heap->call_recursion_limit,
- (long) entry_valstack_bottom_index,
- (long) entry_callstack_top,
- (long) entry_catchstack_top,
- (long) entry_call_recursion_depth,
- (void *) entry_curr_thread,
- (long) entry_thread_state));
-
+ act->reserve_byteoff = 0;
/*
- * Thread state check and book-keeping.
+ * Manipulate valstack so that args are on the current bottom and the
+ * previous caller's 'this' binding (which is the value preceding the
+ * current bottom) is replaced with the new 'this' binding:
+ *
+ * [ ... this_old | (crud) func this_new arg1 ... argN ]
+ * --> [ ... this_new | arg1 ... argN ]
+ *
+ * For tail calling to work properly, the valstack bottom must not grow
+ * here; otherwise crud would accumulate on the valstack.
*/
- if (thr == thr->heap->curr_thread) {
- /* same thread */
- if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
- /* should actually never happen, but check anyway */
- goto thread_state_error;
- }
- } else {
- /* different thread */
- DUK_ASSERT(thr->heap->curr_thread == NULL ||
- thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
- if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
- goto thread_state_error;
- }
- DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
- thr->state = DUK_HTHREAD_STATE_RUNNING;
+ tv1 = thr->valstack_bottom - 1;
+ tv2 = thr->valstack_bottom + idx_func + 1;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
+ DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- /* Note: multiple threads may be simultaneously in the RUNNING
- * state, but not in the same "resume chain".
- */
- }
- DUK_ASSERT(thr->heap->curr_thread == thr);
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+ idx_args = idx_func + 2;
+ duk_remove_n(thr, 0, idx_args); /* may be NORZ */
- /*
- * C call recursion depth check, which provides a reasonable upper
- * bound on maximum C stack size (arbitrary C stack growth is only
- * possible by recursive handle_call / handle_safe_call calls).
- */
+ idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
+ idx_args = 0;
- /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
- * reclimit bump?
- */
+ *out_nargs = ((duk_hcompfunc *) func)->nargs;
+ *out_nregs = ((duk_hcompfunc *) func)->nregs;
+ DUK_ASSERT(*out_nregs >= 0);
+ DUK_ASSERT(*out_nregs >= *out_nargs);
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
- DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
- DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
- if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
- DUK_DD(DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)"));
- } else {
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
- /* XXX: error message is a bit misleading: we reached a recursion
- * limit which is also essentially the same as a C callstack limit
- * (except perhaps with some relaxed threading assumptions).
- */
- DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
- }
- thr->heap->call_recursion_depth++;
- }
- /*
- * Check the function type, handle bound function chains, and prepare
- * parameters for the rest of the call handling. Also figure out the
- * effective 'this' binding, which replaces the current value at
- * idx_func + 1.
- *
- * If the target function is a 'bound' one, follow the chain of 'bound'
- * functions until a non-bound function is found. During this process,
- * bound arguments are 'prepended' to existing ones, and the "this"
- * binding is overridden. See E5 Section 15.3.4.5.1.
- *
- * Lightfunc detection happens here too. Note that lightweight functions
- * can be wrapped by (non-lightweight) bound functions so we must resolve
- * the bound function chain first.
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+#if defined(DUK_USE_TAILCALL)
+#error incorrect options: tail calls enabled with function caller property
+#endif
+ /* XXX: This doesn't actually work properly for tail calls, so
+ * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+ * is in use.
*/
+ duk__update_func_caller_prop(thr, func);
+#endif
- func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
- DUK_TVAL_SET_TVAL(&tv_func_copy, tv_func);
- tv_func = &tv_func_copy; /* local copy to avoid relookups */
+ /* [ ... this_new | arg1 ... argN ] */
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
- DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
- DUK_HOBJECT_IS_NATFUNC(func)));
+ return 1;
+}
+#endif /* DUK_USE_TAILCALL */
- duk__coerce_effective_this_binding(thr, func, idx_func + 1);
- DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_func + 1)));
+DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func,
+ duk_hobject *func,
+ duk_size_t entry_valstack_bottom_byteoff,
+ duk_size_t entry_valstack_end_byteoff,
+ duk_idx_t *out_nargs,
+ duk_idx_t *out_nregs,
+ duk_size_t *out_vs_min_bytes,
+ duk_activation **out_act) {
+ duk_activation *act;
+ duk_activation *new_act;
- /* [ ... func this arg1 ... argN ] */
+ DUK_UNREF(entry_valstack_end_byteoff);
- /*
- * Setup a preliminary activation and figure out nargs/nregs.
- *
- * Don't touch valstack_bottom or valstack_top yet so that Duktape API
- * calls work normally.
- */
+ DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
+ (long) (thr->callstack_top)));
- duk_hthread_callstack_grow(thr);
+ duk__call_callstack_limit_check(thr);
+ new_act = duk_hthread_activation_alloc(thr);
+ DUK_ASSERT(new_act != NULL);
act = thr->callstack_curr;
if (act != NULL) {
/*
- * Update idx_retval of current activation.
+ * Update return value stack index of current activation (if any).
*
* Although it might seem this is not necessary (bytecode executor
* does this for Ecmascript-to-Ecmascript calls; other calls are
* handled here), this turns out to be necessary for handling yield
* and resume. For them, an Ecmascript-to-native call happens, and
- * the Ecmascript call's idx_retval must be set for things to work.
+ * the Ecmascript call's retval_byteoff must be set for things to work.
*/
- act->idx_retval = entry_valstack_bottom_index + idx_func;
+ act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval);
}
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- act = thr->callstack + thr->callstack_top;
+ new_act->parent = act;
+ thr->callstack_curr = new_act;
thr->callstack_top++;
- thr->callstack_curr = act;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
+ act = new_act;
+ *out_act = act;
+
DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */
DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
- act->flags = 0;
+ act->cat = NULL;
- /* For now all calls except Ecma-to-Ecma calls prevent a yield. */
- act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
- if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
+ act->flags = 0;
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
act->flags |= DUK_ACT_FLAG_CONSTRUCT;
}
+#if defined(DUK_USE_ES6_PROXY)
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
+ act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
+ }
+#endif
if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
}
- /* These base values are never used, but if the compiler doesn't know
- * that DUK_ERROR() won't return, these are needed to silence warnings.
- * On the other hand, scan-build will warn about the values not being
- * used, so add a DUK_UNREF.
- */
- nargs = 0; DUK_UNREF(nargs);
- nregs = 0; DUK_UNREF(nregs);
-
+ /* start of arguments: idx_func + 2. */
+ act->func = func; /* NULL for lightfunc */
if (DUK_LIKELY(func != NULL)) {
+ DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
if (DUK_HOBJECT_HAS_STRICT(func)) {
act->flags |= DUK_ACT_FLAG_STRICT;
}
if (DUK_HOBJECT_IS_COMPFUNC(func)) {
- nargs = ((duk_hcompfunc *) func)->nargs;
- nregs = ((duk_hcompfunc *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
+ *out_nargs = ((duk_hcompfunc *) func)->nargs;
+ *out_nregs = ((duk_hcompfunc *) func)->nregs;
+ DUK_ASSERT(*out_nregs >= 0);
+ DUK_ASSERT(*out_nregs >= *out_nargs);
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff +
+ sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
} else {
/* True because of call target lookup checks. */
DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
- /* Note: nargs (and nregs) may be negative for a native,
- * function, which indicates that the function wants the
- * input stack "as is" (i.e. handles "vararg" arguments).
- */
- nargs = ((duk_hnatfunc *) func)->nargs;
- nregs = nargs;
+ *out_nargs = ((duk_hnatfunc *) func)->nargs;
+ *out_nregs = *out_nargs;
+ if (*out_nargs >= 0) {
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff +
+ sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ } else {
+ /* Vararg function. */
+ duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
+ *out_vs_min_bytes = valstack_top_byteoff +
+ sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ }
}
} else {
duk_small_uint_t lf_flags;
+ duk_tval *tv_func;
+ act->flags |= DUK_ACT_FLAG_STRICT;
+
+ tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
+ DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
+
lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
- nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
- if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = -1; /* vararg */
+ *out_nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ if (*out_nargs != DUK_LFUNC_NARGS_VARARGS) {
+ *out_vs_min_bytes = entry_valstack_bottom_byteoff +
+ sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nargs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ } else {
+ duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
+ *out_vs_min_bytes = valstack_top_byteoff +
+ sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
+ *out_nargs = -1; /* vararg */
}
- nregs = nargs;
-
- act->flags |= DUK_ACT_FLAG_STRICT;
+ *out_nregs = *out_nargs;
}
- act->func = func; /* NULL for lightfunc */
act->var_env = NULL;
act->lex_env = NULL;
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
@@ -60977,20 +62707,15 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
#if defined(DUK_USE_DEBUGGER_SUPPORT)
act->prev_line = 0;
#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_func + 2;
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
+ act->bottom_byteoff = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) idx_func + 2U);
+#if 0
+ act->retval_byteoff = 0; /* topmost activation retval_byteoff is considered garbage, no need to init */
#endif
- DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
-
- /* XXX: remove the preventcount and make yield walk the callstack?
- * Or perhaps just use a single flag, not a counter, faster to just
- * set and restore?
+ /* Filled in when final reserve is known, dummy value doesn't matter
+ * even in error unwind because reserve_byteoff is only used when
+ * returning to -this- activation.
*/
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- /* duk_hthread_callstack_unwind() will decrease this on unwind */
- thr->callstack_preventcount++;
- }
+ act->reserve_byteoff = 0; /* filled in by caller */
/* XXX: Is this INCREF necessary? 'func' is always a borrowed
* reference reachable through the value stack? If changed, stack
@@ -61001,26 +62726,18 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
if (func) {
duk__update_func_caller_prop(thr, func);
- act = thr->callstack_curr;
}
#endif
+}
- /* [ ... func this arg1 ... argN ] */
+/*
+ * Environment setup.
+ */
- /*
- * Environment record creation and 'arguments' object creation.
- * Named function expression name binding is handled by the
- * compiler; the compiled function's parent env will contain
- * the (immutable) binding already.
- *
- * This handling is now identical for C and Ecmascript functions.
- * C functions always have the 'NEWENV' flag set, so their
- * environment record initialization is delayed (which is good).
- *
- * Delayed creation (on demand) is handled in duk_js_var.c.
- */
+DUK_LOCAL void duk__call_env_setup(duk_hthread *thr, duk_hobject *func, duk_activation *act, duk_idx_t idx_args) {
+ duk_hobject *env;
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function chain has already been resolved */
+ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function has already been resolved */
if (DUK_LIKELY(func != NULL)) {
if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
@@ -61036,23 +62753,22 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
* We need to initialize it right now.
*/
- /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
+ /* third arg: absolute index (to entire valstack) of bottom_byteoff of new activation */
+ env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
DUK_ASSERT(env != NULL);
/* [ ... func this arg1 ... argN envobj ] */
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
+ duk__handle_createargs_for_call(thr, func, env, idx_args);
/* [ ... func this arg1 ... argN envobj ] */
- act = thr->callstack_curr;
act->lex_env = env;
act->var_env = env;
DUK_HOBJECT_INCREF(thr, env);
DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
- duk_pop(ctx);
+ duk_pop(thr);
}
} else {
/* Use existing env (e.g. for non-strict eval); cannot have
@@ -61062,7 +62778,6 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
duk__handle_oldenv_for_call(thr, func, act);
- /* No need to re-lookup 'act' at present: no side effects. */
DUK_ASSERT(act->lex_env != NULL);
DUK_ASSERT(act->var_env != NULL);
@@ -61072,51 +62787,324 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
DUK_ASSERT(act->lex_env == NULL);
DUK_ASSERT(act->var_env == NULL);
}
+}
+
+/*
+ * Misc shared helpers.
+ */
+
+/* Check thread state, update current thread. */
+DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) {
+ DUK_ASSERT(thr != NULL);
+
+ if (DUK_LIKELY(thr == thr->heap->curr_thread)) {
+ if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_RUNNING)) {
+ /* Should actually never happen, but check anyway. */
+ goto thread_state_error;
+ }
+ } else {
+ DUK_ASSERT(thr->heap->curr_thread == NULL ||
+ thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
+ if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_INACTIVE)) {
+ goto thread_state_error;
+ }
+ DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
+ thr->state = DUK_HTHREAD_STATE_RUNNING;
+
+ /* Multiple threads may be simultaneously in the RUNNING
+ * state, but not in the same "resume chain".
+ */
+ }
+ DUK_ASSERT(thr->heap->curr_thread == thr);
+ DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+ return;
+
+ thread_state_error:
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+}
+
+/*
+ * Main unprotected call handler, handles:
+ *
+ * - All combinations of native/Ecmascript caller and native/Ecmascript
+ * target.
+ *
+ * - Optimized Ecmascript-to-Ecmascript call where call handling only
+ * sets up a new duk_activation but reuses an existing bytecode executor
+ * (the caller) without native recursion.
+ *
+ * - Tailcalls, where an activation is reused without increasing call
+ * stack (duk_activation) depth.
+ *
+ * - Setup for an initial Duktape.Thread.resume().
+ *
+ * The call handler doesn't provide any protection guarantees, protected calls
+ * must be implemented e.g. by wrapping the call in a duk_safe_call().
+ * Call setup may fail at any stage, even when the new activation is in
+ * place; the only guarantee is that the state is consistent for unwinding.
+ */
+
+DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_small_uint_t call_flags) {
+#if defined(DUK_USE_ASSERTIONS)
+ duk_activation *entry_act;
+ duk_size_t entry_callstack_top;
+#endif
+ duk_size_t entry_valstack_bottom_byteoff;
+ duk_size_t entry_valstack_end_byteoff;
+ duk_int_t entry_call_recursion_depth;
+ duk_hthread *entry_curr_thread;
+ duk_uint_fast8_t entry_thread_state;
+ duk_instr_t **entry_ptr_curr_pc;
+ duk_idx_t idx_args;
+ 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") */
+ duk_size_t vs_min_bytes; /* minimum value stack size (bytes) for handling call */
+ duk_hobject *func; /* 'func' on stack (borrowed reference) */
+ duk_activation *act;
+ duk_ret_t rc;
+ duk_small_uint_t use_tailcall;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(thr->heap != NULL);
+ /* Asserts for heap->curr_thread omitted: it may be NULL, 'thr', or
+ * any other thread (e.g. when heap thread is used to run finalizers).
+ */
+ DUK_ASSERT_CTX_VALID(thr);
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ DUK_ASSERT(idx_func >= 0);
+
+ DUK_STATS_INC(thr->heap, stats_call_all);
+
+ /* If a tail call:
+ * - an Ecmascript activation must be on top of the callstack
+ * - there cannot be any catch stack entries that would catch
+ * a return
+ */
+#if defined(DUK_USE_ASSERTIONS)
+ if (call_flags & DUK_CALL_FLAG_TAILCALL) {
+ duk_activation *tmp_act;
+ duk_catcher *tmp_cat;
+
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
+
+ /* No entry in the catch stack which would actually catch a
+ * throw can refer to the callstack entry being reused.
+ * There *can* be catch stack entries referring to the current
+ * callstack entry as long as they don't catch (e.g. label sites).
+ */
+
+ tmp_act = thr->callstack_curr;
+ for (tmp_cat = tmp_act->cat; tmp_cat != NULL; tmp_cat = tmp_cat->parent) {
+ DUK_ASSERT(DUK_CAT_GET_TYPE(tmp_cat) == DUK_CAT_TYPE_LABEL); /* a non-catching entry */
+ }
+ }
+#endif /* DUK_USE_ASSERTIONS */
+
+ /*
+ * Store entry state.
+ */
+
+#if defined(DUK_USE_ASSERTIONS)
+ entry_act = thr->callstack_curr;
+ entry_callstack_top = thr->callstack_top;
+#endif
+ entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
+ entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ entry_call_recursion_depth = thr->heap->call_recursion_depth;
+ entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */
+ entry_thread_state = thr->state;
+ entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
+
+ /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
+ * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
+ * activation when side effects occur.
+ */
+ duk_hthread_sync_and_null_currpc(thr);
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+
+ DUK_DD(DUK_DDPRINT("duk__handle_call_raw: thr=%p, idx_func=%ld, "
+ "call_flags=0x%08lx (constructor=%ld), "
+ "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
+ "entry_valstack_bottom_byteoff=%ld, entry_valstack_end_byteoff=%ld, "
+ "entry_call_recursion_depth=%ld, "
+ "entry_curr_thread=%p, entry_thread_state=%ld",
+ (void *) thr,
+ (long) idx_func,
+ (unsigned long) call_flags,
+ (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) != 0 ? 1 : 0),
+ (long) duk_get_top(thr),
+ (long) idx_func,
+ (long) (idx_func + 2),
+ (long) thr->heap->call_recursion_depth,
+ (long) thr->heap->call_recursion_limit,
+ (long) entry_valstack_bottom_byteoff,
+ (long) entry_valstack_end_byteoff,
+ (long) entry_call_recursion_depth,
+ (void *) entry_curr_thread,
+ (long) entry_thread_state));
+
+ /*
+ * Thread state check and book-keeping.
+ */
+
+ duk__call_thread_state_update(thr);
+
+ /*
+ * Resolve final target function; handle bound functions and special
+ * functions like .call() and .apply(). Also figure out the effective
+ * 'this' binding, which replaces the current value at idx_func + 1.
+ */
+
+ if (DUK_LIKELY(duk__resolve_target_fastpath_check(thr, idx_func, &func, call_flags) != 0U)) {
+ DUK_DDD(DUK_DDDPRINT("fast path target resolve"));
+ } else {
+ DUK_DDD(DUK_DDDPRINT("slow path target resolve"));
+ func = duk__resolve_target_func_and_this_binding(thr, idx_func, &call_flags);
+ }
+ DUK_ASSERT(duk_get_top(thr) - idx_func >= 2); /* at least func and this present */
+
+ DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
+ DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
+ DUK_HOBJECT_IS_NATFUNC(func)));
/* [ ... func this arg1 ... argN ] */
/*
- * Setup value stack: clamp to 'nargs', fill up to 'nregs'
+ * Setup a preliminary activation and figure out nargs/nregs and
+ * value stack minimum size.
*
- * Value stack may either grow or shrink, depending on the
- * number of func registers and the number of actual arguments.
- * If nregs >= 0, func wants args clamped to 'nargs'; else it
- * wants all args (= 'num_stack_args').
+ * Don't touch valstack_bottom or valstack_top yet so that Duktape API
+ * calls work normally.
+ *
+ * Because 'act' is not zeroed, all fields must be filled in.
*/
- /* XXX: optimize value stack operation */
- /* XXX: don't want to shrink allocation here */
+#if defined(DUK_USE_TAILCALL)
+ use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL);
+ if (use_tailcall) {
+ use_tailcall = duk__call_setup_act_attempt_tailcall(thr,
+ call_flags,
+ idx_func,
+ func,
+ entry_valstack_bottom_byteoff,
+ entry_valstack_end_byteoff,
+ &nargs,
+ &nregs,
+ &vs_min_bytes,
+ &act);
+ }
+#else
+ DUK_ASSERT((call_flags & DUK_CALL_FLAG_TAILCALL) == 0); /* compiler ensures this */
+ use_tailcall = 0;
+#endif
- duk__adjust_valstack_and_top(thr,
- num_stack_args,
- idx_func + 2,
- nregs,
- nargs,
- func);
+ if (use_tailcall) {
+ idx_args = 0;
+ DUK_STATS_INC(thr->heap, stats_call_tailcall);
+ } else {
+ duk__call_setup_act_not_tailcall(thr,
+ call_flags,
+ idx_func,
+ func,
+ entry_valstack_bottom_byteoff,
+ entry_valstack_end_byteoff,
+ &nargs,
+ &nregs,
+ &vs_min_bytes,
+ &act);
+ idx_args = idx_func + 2;
+ }
+ /* After this point idx_func is no longer valid for tailcalls. */
+
+ DUK_ASSERT(act != NULL);
+
+ /* [ ... func this arg1 ... argN ] */
/*
- * Determine call type, then finalize activation, shift to
- * new value stack bottom, and call the target.
+ * Environment record creation and 'arguments' object creation.
+ * Named function expression name binding is handled by the
+ * compiler; the compiled function's parent env will contain
+ * the (immutable) binding already.
+ *
+ * This handling is now identical for C and Ecmascript functions.
+ * C functions always have the 'NEWENV' flag set, so their
+ * environment record initialization is delayed (which is good).
+ *
+ * Delayed creation (on demand) is handled in duk_js_var.c.
+ */
+
+ duk__call_env_setup(thr, func, act, idx_args);
+
+ /* [ ... func this arg1 ... argN ] */
+
+ /*
+ * Setup value stack: clamp to 'nargs', fill up to 'nregs',
+ * ensure value stack size matches target requirements, and
+ * switch value stack bottom. Valstack top is kept.
+ *
+ * Value stack can only grow here.
+ */
+
+ duk_valstack_grow_check_throw(thr, vs_min_bytes);
+ act->reserve_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+
+ if (use_tailcall) {
+ DUK_ASSERT(nregs >= 0);
+ DUK_ASSERT(nregs >= nargs);
+ duk_set_top_and_wipe(thr, nregs, nargs);
+ } else {
+ if (nregs >= 0) {
+ DUK_ASSERT(nregs >= nargs);
+ duk_set_top_and_wipe(thr, idx_func + 2 + nregs, idx_func + 2 + nargs);
+ } else {
+ ;
+ }
+ thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
+ }
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+
+ /*
+ * Make the actual call. For Ecma-to-Ecma calls detect that
+ * setup is complete, then return with a status code that allows
+ * the caller to reuse the running executor.
*/
- act = thr->callstack_curr;
if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) {
/*
- * Ecmascript call
+ * Ecmascript call.
*/
- duk_tval *tv_ret;
- duk_tval *tv_funret;
-
DUK_ASSERT(func != NULL);
DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
- thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ if (call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA) {
+ DUK_DD(DUK_DDPRINT("avoid native call, use existing executor"));
+ DUK_STATS_INC(thr->heap, stats_call_ecmatoecma);
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ DUK_REFZERO_CHECK_FAST(thr);
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ return 1; /* 1=reuse executor */
+ }
+ DUK_ASSERT(use_tailcall == 0);
+
+ /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
+ thr->callstack_preventcount++;
+
+ /* XXX: we could just do this on entry regardless of reuse, as long
+ * as recursion depth is decreased for e2e case.
+ */
+ duk__call_c_recursion_limit_check(thr);
+ thr->heap->call_recursion_depth++;
/* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
@@ -61137,124 +63125,123 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
duk_js_execute_bytecode(thr);
DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
-
- /* Unwind. */
-
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
- duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top);
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_unwind_norz(thr, entry_callstack_top); /* XXX: may now fail */
- duk_hthread_callstack_shrink_check(thr);
-
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
-
- /* Return value handling. */
-
- /* [ ... func this (crud) retval ] */
-
- tv_ret = thr->valstack_bottom + idx_func;
- tv_funret = thr->valstack_top - 1;
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
-#endif
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
} else {
/*
* Native call.
*/
- duk_tval *tv_ret;
- duk_tval *tv_funret;
-
- thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
DUK_ASSERT(func == NULL || ((duk_hnatfunc *) func)->func != NULL);
+ DUK_ASSERT(use_tailcall == 0);
/* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
+ /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
+ DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
+ act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
+ thr->callstack_preventcount++;
+
+ /* XXX: we could just do this on entry regardless of reuse, as long
+ * as recursion depth is decreased for e2e case.
+ */
+ duk__call_c_recursion_limit_check(thr);
+ thr->heap->call_recursion_depth++;
+
/* For native calls must be NULL so we don't sync back */
DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ /* XXX: native funcptr could come out of call setup. */
if (func) {
- rc = ((duk_hnatfunc *) func)->func((duk_context *) thr);
+ rc = ((duk_hnatfunc *) func)->func(thr);
} else {
- duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
- rc = funcptr((duk_context *) thr);
+ duk_tval *tv_func;
+ duk_c_function funcptr;
+
+ tv_func = &act->tv_func;
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
+ funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
+ rc = funcptr(thr);
}
/* Automatic error throwing, retval check. */
- if (rc < 0) {
+ if (rc == 0) {
+ DUK_ASSERT(thr->valstack < thr->valstack_end);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
+ thr->valstack_top++;
+ } else if (rc == 1) {
+ ;
+ } else if (rc < 0) {
duk_error_throw_from_negative_rc(thr, rc);
DUK_UNREACHABLE();
- } else if (rc > 1) {
- DUK_ERROR_TYPE(thr, "c function returned invalid rc");
+ } else {
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
}
- DUK_ASSERT(rc == 0 || rc == 1);
+ }
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ DUK_ASSERT(use_tailcall == 0);
+
+ /*
+ * Constructor call post processing.
+ */
+
+#if defined(DUK_USE_ES6_PROXY)
+ if (call_flags & (DUK_CALL_FLAG_CONSTRUCT | DUK_CALL_FLAG_CONSTRUCT_PROXY)) {
+ duk_call_construct_postprocess(thr, call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY);
+ }
+#else
+ if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
+ duk_call_construct_postprocess(thr, 0);
+ }
+#endif
+
+ /*
+ * Unwind, restore valstack bottom and other book-keeping.
+ */
+
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent == entry_act);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ duk_hthread_activation_unwind_norz(thr);
+ DUK_ASSERT(thr->callstack_curr == entry_act);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
- /* Unwind. */
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
- duk_hthread_callstack_unwind_norz(thr, entry_callstack_top);
- duk_hthread_callstack_shrink_check(thr);
+ /* Return value handling. */
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
+ /* [ ... func this (crud) retval ] */
- /* Return value handling. */
+ {
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- /* XXX: should this happen in the callee's activation or after unwinding? */
tv_ret = thr->valstack_bottom + idx_func;
- if (rc == 0) {
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv_ret); /* side effects */
- } else {
- /* [ ... func this (crud) retval ] */
- tv_funret = thr->valstack_top - 1;
+ tv_funret = thr->valstack_top - 1;
#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
#endif
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
- }
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
}
- duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
+ duk_set_top_unsafe(thr, idx_func + 1);
/* [ ... retval ] */
- /* Ensure there is internal valstack spare before we exit; this may
- * throw an alloc error. The same guaranteed size must be available
- * as before the call. This is not optimal now: we store the valstack
- * allocated size during entry; this value may be higher than the
- * minimal guarantee for an application.
- */
+ /* Restore caller's value stack reserve (cannot fail). */
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff >= (duk_uint8_t *) thr->valstack_top);
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff <= (duk_uint8_t *) thr->valstack_alloc_end);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff);
- /* XXX: we should never shrink here; when we error out later, we'd
- * need to potentially grow the value stack in error unwind which could
- * cause another error.
+ /* XXX: Trial value stack shrink would be OK here, but we'd need
+ * to prevent side effects of the potential realloc.
*/
- (void) duk_valstack_resize_raw((duk_context *) thr,
- entry_valstack_end, /* same as during entry */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- DUK_VSRESIZE_FLAG_COMPACT |
- DUK_VSRESIZE_FLAG_THROW);
-
/* Restore entry thread executor curr_pc stack frame pointer. */
thr->ptr_curr_pc = entry_ptr_curr_pc;
@@ -61295,162 +63282,29 @@ DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
/* Restored by success path. */
DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
-
DUK_ASSERT_LJSTATE_UNSET(thr->heap);
DUK_REFZERO_CHECK_FAST(thr);
- return;
-
- thread_state_error:
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return; /* never executed */
+ return 0; /* 0=call handled inline */
}
-DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_valstack_end,
- duk_size_t entry_catchstack_top,
- duk_size_t entry_callstack_top,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc,
- duk_idx_t idx_func,
- duk_jmpbuf *old_jmpbuf_ptr) {
- duk_context *ctx;
- duk_tval *tv_ret;
-
- ctx = (duk_context *) thr;
-
- DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
- (duk_tval *) &thr->heap->lj.value1));
-
- /* Other longjmp types are handled by executor before propagating
- * the error here.
- */
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT_LJSTATE_SET(thr->heap);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
-
- /* We don't need to sync back thr->ptr_curr_pc here because
- * the bytecode executor always has a setjmp catchpoint which
- * does that before errors propagate to here.
- */
- DUK_ASSERT(thr->ptr_curr_pc == NULL);
-
- /* Restore the previous setjmp catcher so that any error in
- * error handling will propagate outwards rather than re-enter
- * the same handler. However, the error handling path must be
- * designed to be error free so that sandboxing guarantees are
- * reliable, see e.g. https://github.com/svaarala/duktape/issues/476.
- */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- /* XXX: callstack unwind may now throw an error when closing
- * scopes; this is a sandboxing issue, described in:
- * https://github.com/svaarala/duktape/issues/476
- */
- duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top);
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_unwind_norz(thr, entry_callstack_top);
- duk_hthread_callstack_shrink_check(thr);
-
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- tv_ret = thr->valstack_bottom + idx_func; /* XXX: byte offset? */
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE_FAST(tv_ret);
-#endif
- duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
-
- /* [ ... errobj ] */
-
- /* Ensure there is internal valstack spare before we exit; this may
- * throw an alloc error. The same guaranteed size must be available
- * as before the call. This is not optimal now: we store the valstack
- * allocated size during entry; this value may be higher than the
- * minimal guarantee for an application.
- */
-
- /* XXX: this needs to be reworked so that we never shrink the value
- * stack on function entry so that we never need to grow it here.
- * Needing to grow here is a sandboxing issue because we need to
- * allocate which may cause an error in the error handling path
- * and thus propagate an error out of a protected call.
- */
-
- (void) duk_valstack_resize_raw((duk_context *) thr,
- entry_valstack_end, /* same as during entry */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- DUK_VSRESIZE_FLAG_COMPACT |
- DUK_VSRESIZE_FLAG_THROW);
-
-
- /* These are just convenience "wiping" of state. Side effects should
- * not be an issue here: thr->heap and thr->heap->lj have a stable
- * pointer. Finalizer runs etc capture even out-of-memory errors so
- * nothing should throw here.
- */
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
-
- /* Restore entry thread executor curr_pc stack frame pointer. */
- thr->ptr_curr_pc = entry_ptr_curr_pc;
-
- DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
- thr->state = (duk_uint8_t) entry_thread_state;
-
- /* Disabled assert: triggered with some torture tests. */
-#if 0
- DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
- (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
- (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
-#endif
-
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* If the debugger is active we need to force an interrupt so that
- * debugger breakpoints are rechecked. This is important for function
- * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
- * GH-303. Only needed for success path, error path always causes a
- * breakpoint recheck in the executor. It would be enough to set this
- * only when returning to an Ecmascript activation, but setting the flag
- * on every return should have no ill effect.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (duk_debug_is_attached(thr->heap)) {
- DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
- DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
- thr->interrupt_init -= thr->interrupt_counter;
- thr->interrupt_counter = 0;
- thr->heap->dbg_force_restart = 1;
- }
-#endif
-
-#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
- duk__interrupt_fixup(thr, entry_curr_thread);
-#endif
-
- /* Error handling complete, remove side effect protections and
- * process pending finalizers.
- */
-#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(thr->heap->error_not_allowed == 1);
- thr->heap->error_not_allowed = 0;
-#endif
- DUK_ASSERT(thr->heap->pf_prevent_count > 0);
- thr->heap->pf_prevent_count--;
- DUK_DD(DUK_DDPRINT("call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count));
-
- DUK_ASSERT_LJSTATE_UNSET(thr->heap);
+DUK_INTERNAL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr,
+ duk_idx_t nargs,
+ duk_small_uint_t call_flags) {
+ duk_idx_t idx_func;
+ DUK_ASSERT(duk_get_top(thr) >= nargs + 2);
+ idx_func = duk_get_top(thr) - (nargs + 2);
+ DUK_ASSERT(idx_func >= 0);
+ return duk_handle_call_unprotected(thr, idx_func, call_flags);
+}
- DUK_REFZERO_CHECK_SLOW(thr);
+DUK_INTERNAL duk_int_t duk_handle_call_unprotected(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_small_uint_t call_flags) {
+ DUK_ASSERT(duk_is_valid_index(thr, idx_func));
+ DUK_ASSERT(idx_func >= 0);
+ return duk__handle_call_raw(thr, idx_func, call_flags);
}
/*
@@ -61458,247 +63312,52 @@ DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
* current activation.
*
* The allowed thread states for making a call are the same as for
- * duk_handle_call_xxx().
+ * duk_handle_call_protected().
*
- * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
- * (and result in a fatal error) for insane arguments.
+ * Even though this call is protected, errors are thrown for insane arguments
+ * and may result in a fatal error unless there's another protected call which
+ * catches such errors.
+ *
+ * The error handling path should be error free, even for out-of-memory
+ * errors, to ensure safe sandboxing. (As of Duktape 2.2.0 this is not
+ * yet the case for environment closing which may run out of memory, see
+ * XXX notes below.)
*/
-/* XXX: bump preventcount by one for the duration of this call? */
-
-DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
- duk_safe_call_function func,
- void *udata,
- duk_idx_t num_stack_args,
- duk_idx_t num_stack_rets) {
- duk_context *ctx = (duk_context *) thr;
- duk_size_t entry_valstack_bottom_index;
- duk_size_t entry_callstack_top;
- duk_size_t entry_catchstack_top;
- duk_int_t entry_call_recursion_depth;
- duk_hthread *entry_curr_thread;
- duk_uint_fast8_t entry_thread_state;
- duk_instr_t **entry_ptr_curr_pc;
- duk_jmpbuf *old_jmpbuf_ptr = NULL;
- duk_jmpbuf our_jmpbuf;
- duk_idx_t idx_retbase;
- duk_int_t retval;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
-
- /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
- entry_callstack_top = thr->callstack_top;
- entry_catchstack_top = thr->catchstack_top;
- entry_call_recursion_depth = thr->heap->call_recursion_depth;
- entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
- entry_thread_state = thr->state;
- entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
- idx_retbase = duk_get_top(ctx) - num_stack_args; /* Note: not a valid stack index if num_stack_args == 0 */
-
- /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
- DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
- "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
- "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
- "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
- (void *) thr,
- (long) num_stack_args,
- (long) num_stack_rets,
- (long) duk_get_top(ctx),
- (long) idx_retbase,
- (long) thr->heap->call_recursion_depth,
- (long) thr->heap->call_recursion_limit,
- (long) entry_valstack_bottom_index,
- (long) entry_callstack_top,
- (long) entry_catchstack_top,
- (long) entry_call_recursion_depth,
- (void *) entry_curr_thread,
- (long) entry_thread_state));
-
- if (idx_retbase < 0) {
- /* Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
- */
-
- DUK_ERROR_TYPE_INVALID_ARGS(thr);
- }
-
- /* setjmp catchpoint setup */
-
- old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
- thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- try {
-#else
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
- if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
- /* Success path. */
-#endif
- DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
-
- duk__handle_safe_call_inner(thr,
- func,
- udata,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top);
-
- /* Note: either pointer may be NULL (at entry), so don't assert */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- retval = DUK_EXEC_SUCCESS;
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- } catch (duk_internal_exception &exc) {
- DUK_UNREF(exc);
-#else
- } else {
- /* Error path. */
-#endif
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
-
- retval = DUK_EXEC_ERROR;
- }
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- catch (std::exception &exc) {
- const char *what = exc.what();
- if (!what) {
- what = "unknown";
- }
- DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
- DUK_UNREF(exc);
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
- retval = DUK_EXEC_ERROR;
- }
- } catch (...) {
- DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
- } catch (duk_internal_exception exc) {
- DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
- DUK_UNREF(exc);
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
- retval = DUK_EXEC_ERROR;
- }
- }
-#endif
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
-
- DUK_ASSERT_LJSTATE_UNSET(thr->heap);
-
- duk__handle_safe_call_shared(thr,
- idx_retbase,
- num_stack_rets,
- entry_call_recursion_depth,
- entry_curr_thread,
- entry_thread_state,
- entry_ptr_curr_pc);
-
- return retval;
-}
-
DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
duk_safe_call_function func,
void *udata,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_valstack_bottom_byteoff,
duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top) {
- duk_context *ctx;
+#endif
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets) {
duk_ret_t rc;
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(entry_valstack_bottom_index);
- DUK_UNREF(entry_callstack_top);
- DUK_UNREF(entry_catchstack_top);
+ DUK_ASSERT_CTX_VALID(thr);
/*
* Thread state check and book-keeping.
*/
- if (thr == thr->heap->curr_thread) {
- /* same thread */
- if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
- /* should actually never happen, but check anyway */
- goto thread_state_error;
- }
- } else {
- /* different thread */
- DUK_ASSERT(thr->heap->curr_thread == NULL ||
- thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
- if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
- goto thread_state_error;
- }
- DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
- thr->state = DUK_HTHREAD_STATE_RUNNING;
-
- /* Note: multiple threads may be simultaneously in the RUNNING
- * state, but not in the same "resume chain".
- */
- }
-
- DUK_ASSERT(thr->heap->curr_thread == thr);
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
+ duk__call_thread_state_update(thr);
/*
* Recursion limit check.
- *
- * Note: there is no need for an "ignore recursion limit" flag
- * for duk_handle_safe_call now.
*/
- DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
- DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
- /* XXX: error message is a bit misleading: we reached a recursion
- * limit which is also essentially the same as a C callstack limit
- * (except perhaps with some relaxed threading assumptions).
- */
- DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
- }
+ duk__call_c_recursion_limit_check(thr);
thr->heap->call_recursion_depth++;
/*
- * Valstack spare check
- */
-
- duk_require_stack(ctx, 0); /* internal spare */
-
- /*
- * Make the C call
+ * Make the C call.
*/
- rc = func(ctx, udata);
+ rc = func(thr, udata);
DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
@@ -61708,48 +63367,35 @@ DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
/* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
DUK_ASSERT(thr->callstack_top == entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT((duk_size_t) (thr->valstack_bottom - thr->valstack) == entry_valstack_bottom_index);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- if (rc < 0) {
+ if (DUK_UNLIKELY(rc < 0)) {
duk_error_throw_from_negative_rc(thr, rc);
}
DUK_ASSERT(rc >= 0);
- if (duk_get_top(ctx) < rc) {
- DUK_ERROR_RANGE(thr, "not enough stack values for safe_call rc");
- }
-
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
- DUK_ASSERT(thr->callstack_top == entry_callstack_top);
-
- duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
-
- DUK_ASSERT_LJSTATE_UNSET(thr->heap);
-
- DUK_REFZERO_CHECK_FAST(thr);
- return;
+ duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); /* throws for insane rc */
- thread_state_error:
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
+ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
+ thr->state = (duk_uint8_t) entry_thread_state;
}
DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
+ duk_activation *entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_callstack_top,
+#endif
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
duk_idx_t idx_retbase,
duk_idx_t num_stack_rets,
- duk_size_t entry_valstack_bottom_index,
- duk_size_t entry_callstack_top,
- duk_size_t entry_catchstack_top,
+ duk_size_t entry_valstack_bottom_byteoff,
duk_jmpbuf *old_jmpbuf_ptr) {
- duk_context *ctx;
-
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
- DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
/*
* Error during call. The error value is at heap->lj.value1.
@@ -61766,51 +63412,56 @@ DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
*/
DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
DUK_ASSERT_LJSTATE_SET(thr->heap);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
- /* Note: either pointer may be NULL (at entry), so don't assert. */
+ /* Either pointer may be NULL (at entry), so don't assert. */
thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+ /* XXX: callstack unwind may now throw an error when closing
+ * scopes; this is a sandboxing issue, described in:
+ * https://github.com/svaarala/duktape/issues/476
+ */
+ /* XXX: "unwind to" primitive? */
+
DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- duk_hthread_catchstack_unwind_norz(thr, entry_catchstack_top);
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_unwind_norz(thr, entry_callstack_top);
- duk_hthread_callstack_shrink_check(thr);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ while (thr->callstack_curr != entry_act) {
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ duk_hthread_activation_unwind_norz(thr);
+ }
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
+
+ /* Switch active thread before any side effects to avoid a
+ * dangling curr_thread pointer.
+ */
+ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
+ thr->state = (duk_uint8_t) entry_thread_state;
+
+ DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
+ DUK_ASSERT(thr->state == entry_thread_state);
+
+ /* Restore valstack bottom. */
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
/* [ ... | (crud) ] */
- /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
- duk_push_tval(ctx, &thr->heap->lj.value1);
+ /* XXX: ensure space in valstack (now relies on internal reserve)? */
+ duk_push_tval(thr, &thr->heap->lj.value1);
/* [ ... | (crud) errobj ] */
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
-
- /* check that the valstack has space for the final amount and any
- * intermediate space needed; this is unoptimal but should be safe
- */
- duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
- duk_require_stack(ctx, num_stack_rets);
+ DUK_ASSERT(duk_get_top(thr) >= 1); /* at least errobj must be on stack */
duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
/* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
- /* These are just convenience "wiping" of state. Side effects should
- * not be an issue here: thr->heap and thr->heap->lj have a stable
- * pointer. Finalizer runs etc capture even out-of-memory errors so
- * nothing should throw here.
- */
+ /* Reset longjmp state. */
thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
thr->heap->lj.iserror = 0;
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value1);
+ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value2);
- /* Error handling complete, remove side effect protections and
- * process pending finalizers.
+ /* Error handling complete, remove side effect protections. Caller
+ * will process pending finalizers.
*/
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(thr->heap->error_not_allowed == 1);
@@ -61820,47 +63471,39 @@ DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
thr->heap->pf_prevent_count--;
DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count));
- DUK_ASSERT_LJSTATE_UNSET(thr->heap);
-
- DUK_REFZERO_CHECK_SLOW(thr);
+ /* thr->ptr_curr_pc is restored by
+ * duk__handle_safe_call_shared_unwind() which is also used for
+ * success path.
+ */
}
-DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
- duk_idx_t idx_retbase,
- duk_idx_t num_stack_rets,
- duk_int_t entry_call_recursion_depth,
- duk_hthread *entry_curr_thread,
- duk_uint_fast8_t entry_thread_state,
- duk_instr_t **entry_ptr_curr_pc) {
- duk_context *ctx;
-
+DUK_LOCAL void duk__handle_safe_call_shared_unwind(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_callstack_top,
+#endif
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_instr_t **entry_ptr_curr_pc) {
DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
+ DUK_ASSERT_CTX_VALID(thr);
DUK_UNREF(idx_retbase);
DUK_UNREF(num_stack_rets);
+ DUK_UNREF(entry_curr_thread);
- /* Restore entry thread executor curr_pc stack frame pointer. */
- thr->ptr_curr_pc = entry_ptr_curr_pc;
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
- /* XXX: because we unwind stacks above, thr->heap->curr_thread is at
- * risk of pointing to an already freed thread. This was indeed the
- * case in test-bug-multithread-valgrind.c, until duk_handle_call()
- * was fixed to restore thr->heap->curr_thread before rethrowing an
- * uncaught error.
+ /* Restore entry thread executor curr_pc stack frame pointer.
+ * XXX: would be enough to do in error path only, should nest
+ * cleanly in success path.
*/
- DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
- thr->state = (duk_uint8_t) entry_thread_state;
-
- DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
- (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
- (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
+ thr->ptr_curr_pc = entry_ptr_curr_pc;
thr->heap->call_recursion_depth = entry_call_recursion_depth;
/* stack discipline consistency check */
- DUK_ASSERT(duk_get_top(ctx) == idx_retbase + num_stack_rets);
+ DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
/* A debugger forced interrupt check is not needed here, as
* problematic safe calls are not caused by side effects.
@@ -61869,479 +63512,293 @@ DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
-
- DUK_ASSERT_LJSTATE_UNSET(thr->heap);
}
-/*
- * Helper for handling an Ecmascript-to-Ecmascript call or an Ecmascript
- * function (initial) Duktape.Thread.resume().
- *
- * Compared to normal calls handled by duk_handle_call(), there are a
- * bunch of differences:
- *
- * - the call is never protected
- * - there is no C recursion depth increase (hence an "ignore recursion
- * limit" flag is not applicable)
- * - instead of making the call, this helper just performs the thread
- * setup and returns; the bytecode executor then restarts execution
- * internally
- * - ecmascript functions are never 'vararg' functions (they access
- * varargs through the 'arguments' object)
- *
- * The callstack of the target contains an earlier Ecmascript call in case
- * of an Ecmascript-to-Ecmascript call (whose idx_retval is updated), or
- * is empty in case of an initial Duktape.Thread.resume().
- *
- * The first thing to do here is to figure out whether an ecma-to-ecma
- * call is actually possible. It's not always the case if the target is
- * a bound function; the final function may be native. In that case,
- * return an error so caller can fall back to a normal call path.
- */
-
-DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_size_t entry_valstack_bottom_index;
- 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 => never for ecma calls) */
- duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => never for ecma calls) */
- duk_hobject *func; /* 'func' on stack (borrowed reference) */
- duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) */
- duk_activation *act;
- duk_hobject *env;
- duk_bool_t use_tailcall;
+DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
+ duk_safe_call_function func,
+ void *udata,
+ duk_idx_t num_stack_args,
+ duk_idx_t num_stack_rets) {
+ duk_activation *entry_act;
+ duk_size_t entry_valstack_bottom_byteoff;
+#if defined(DUK_USE_ASSERTIONS)
+ duk_size_t entry_valstack_end_byteoff;
+ duk_size_t entry_callstack_top;
+ duk_size_t entry_callstack_preventcount;
+#endif
+ duk_int_t entry_call_recursion_depth;
+ duk_hthread *entry_curr_thread;
+ duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
+ duk_jmpbuf *old_jmpbuf_ptr = NULL;
+ duk_jmpbuf our_jmpbuf;
+ duk_idx_t idx_retbase;
+ duk_int_t retval;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
+ DUK_ASSERT(duk_get_top(thr) >= num_stack_args); /* Caller ensures. */
- /* XXX: assume these? */
- DUK_ASSERT(thr->valstack != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->catchstack != NULL);
+ DUK_STATS_INC(thr->heap, stats_safecall_all);
- /* no need to handle thread state book-keeping here */
- DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
- (thr->state == DUK_HTHREAD_STATE_RUNNING &&
- thr->heap->curr_thread == thr));
-
- /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
- * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
- * activation when side effects occur. If we end up not making the
- * call we must restore the value.
+ /* Value stack reserve handling: safe call assumes caller has reserved
+ * space for nrets (assuming optimal unwind processing). Value stack
+ * reserve is not stored/restored as for normal calls because a safe
+ * call conceptually happens in the same activation.
*/
- entry_ptr_curr_pc = thr->ptr_curr_pc;
- duk_hthread_sync_and_null_currpc(thr);
- /* if a tail call:
- * - an Ecmascript activation must be on top of the callstack
- * - there cannot be any active catchstack entries
- */
+ /* Careful with indices like '-x'; if 'x' is zero, it refers to bottom */
+ entry_act = thr->callstack_curr;
+ entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
#if defined(DUK_USE_ASSERTIONS)
- if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
- duk_size_t our_callstack_index;
- duk_size_t i;
-
- DUK_ASSERT(thr->callstack_top >= 1);
- our_callstack_index = thr->callstack_top - 1;
- DUK_ASSERT_DISABLE(our_callstack_index >= 0);
- DUK_ASSERT(our_callstack_index < thr->callstack_size);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index)));
-
- /* No entry in the catchstack which would actually catch a
- * throw can refer to the callstack entry being reused.
- * There *can* be catchstack entries referring to the current
- * callstack entry as long as they don't catch (e.g. label sites).
- */
-
- for (i = 0; i < thr->catchstack_top; i++) {
- DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index || /* refer to callstack entries below current */
- DUK_CAT_GET_TYPE(thr->catchstack + i) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
- }
- }
-#endif /* DUK_USE_ASSERTIONS */
+ entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
+ entry_callstack_top = thr->callstack_top;
+ entry_callstack_preventcount = thr->callstack_preventcount;
+#endif
+ entry_call_recursion_depth = thr->heap->call_recursion_depth;
+ entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */
+ entry_thread_state = thr->state;
+ entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
+ idx_retbase = duk_get_top(thr) - num_stack_args; /* not a valid stack index if num_stack_args == 0 */
+ DUK_ASSERT(idx_retbase >= 0);
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
- /* XXX: rework */
- idx_func = duk_normalize_index(thr, -num_stack_args - 2);
- idx_args = idx_func + 2;
+ DUK_ASSERT((duk_idx_t) (thr->valstack_top - thr->valstack_bottom) >= num_stack_args); /* Caller ensures. */
+ DUK_ASSERT((duk_idx_t) (thr->valstack_end - (thr->valstack_bottom + idx_retbase)) >= num_stack_rets); /* Caller ensures. */
- DUK_DD(DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
- "num_stack_args=%ld, call_flags=0x%08lx (resume=%ld, tailcall=%ld), "
- "idx_func=%ld, idx_args=%ld, entry_valstack_bottom_index=%ld",
+ /* Cannot portably debug print a function pointer, hence 'func' not printed! */
+ DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
+ "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
+ "entry_act=%p, entry_valstack_bottom_byteoff=%ld, entry_call_recursion_depth=%ld, "
+ "entry_curr_thread=%p, entry_thread_state=%ld",
(void *) thr,
(long) num_stack_args,
- (unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
- (long) ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
- (long) idx_func,
- (long) idx_args,
- (long) entry_valstack_bottom_index));
+ (long) num_stack_rets,
+ (long) duk_get_top(thr),
+ (long) idx_retbase,
+ (long) thr->heap->call_recursion_depth,
+ (long) thr->heap->call_recursion_limit,
+ (void *) entry_act,
+ (long) entry_valstack_bottom_byteoff,
+ (long) entry_call_recursion_depth,
+ (void *) entry_curr_thread,
+ (long) entry_thread_state));
- if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
- /* XXX: assert? compiler is responsible for this never happening */
- DUK_ERROR_TYPE_INVALID_ARGS(thr);
- }
+ /* Setjmp catchpoint setup. */
+ old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
+ thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
- /*
- * Check the function type, handle bound function chains, and prepare
- * parameters for the rest of the call handling. Also figure out the
- * effective 'this' binding, which replaces the current value at
- * idx_func + 1.
- *
- * If the target function is a 'bound' one, follow the chain of 'bound'
- * functions until a non-bound function is found. During this process,
- * bound arguments are 'prepended' to existing ones, and the "this"
- * binding is overridden. See E5 Section 15.3.4.5.1.
- *
- * If the final target function cannot be handled by an ecma-to-ecma
- * call, return to the caller with a return value indicating this case.
- * The bound chain is resolved and the caller can resume with a plain
- * function call.
+ /* Prevent yields for the duration of the safe call. This only
+ * matters if the executor makes safe calls to functions that
+ * yield, this doesn't currently happen.
*/
+ thr->callstack_preventcount++;
- func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
- if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) {
- DUK_DDD(DUK_DDDPRINT("final target is a lightfunc/nativefunc, cannot do ecma-to-ecma call"));
- thr->ptr_curr_pc = entry_ptr_curr_pc;
- return 0;
- }
- /* XXX: tv_func is not actually needed */
-
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
- DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func));
-
- duk__coerce_effective_this_binding(thr, func, idx_func + 1);
- DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
- duk_get_tval(ctx, idx_func + 1)));
-
- nargs = ((duk_hcompfunc *) func)->nargs;
- nregs = ((duk_hcompfunc *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
-
- /* [ ... func this arg1 ... argN ] */
-
- /*
- * Preliminary activation record and valstack manipulation.
- * The concrete actions depend on whether the we're dealing
- * with a tail call (reuse an existing activation), a resume,
- * or a normal call.
- *
- * The basic actions, in varying order, are:
- *
- * - Check stack size for call handling
- * - Grow call stack if necessary (non-tail-calls)
- * - Update current activation (idx_retval) if necessary
- * (non-tail, non-resume calls)
- * - Move start of args (idx_args) to valstack bottom
- * (tail calls)
- *
- * Don't touch valstack_bottom or valstack_top yet so that Duktape API
- * calls work normally.
- */
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
+ if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
+ /* Success path. */
+#endif
+ DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
- /* XXX: some overlapping code; cleanup */
- use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
-#if !defined(DUK_USE_TAILCALL)
- DUK_ASSERT(use_tailcall == 0); /* compiler ensures this */
+ duk__handle_safe_call_inner(thr,
+ func,
+ udata,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_valstack_bottom_byteoff,
+ entry_callstack_top,
#endif
- if (use_tailcall) {
- /* tailcall cannot be flagged to resume calls, and a
- * previous frame must exist
- */
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0);
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets);
- act = thr->callstack_curr;
- DUK_ASSERT(act != NULL);
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- /* See: test-bug-tailcall-preventyield-assert.c. */
- DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
- use_tailcall = 0;
- } else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
- DUK_D(DUK_DPRINT("tail call prevented by function having a notail flag"));
- use_tailcall = 0;
- }
- }
+ DUK_STATS_INC(thr->heap, stats_safecall_nothrow);
- if (use_tailcall) {
- duk_tval *tv1, *tv2;
- duk_size_t cs_index;
- duk_int_t i_stk; /* must be signed for loop structure */
- duk_idx_t i_arg;
+ /* Either pointer may be NULL (at entry), so don't assert */
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
- /*
- * Tailcall handling
- *
- * Although the callstack entry is reused, we need to explicitly unwind
- * the current activation (or simulate an unwind). In particular, the
- * current activation must be closed, otherwise something like
- * test-bug-reduce-judofyr.js results. Also catchstack needs be unwound
- * because there may be non-error-catching label entries in valid tail calls.
+ /* If calls happen inside the safe call, these are restored by
+ * whatever calls are made. Reserve cannot decrease.
*/
+ DUK_ASSERT(thr->callstack_curr == entry_act);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
- DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
- (long) (thr->callstack_top - 1)));
-
- /* 'act' already set above */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
- DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
-
- /* Unwind catchstack entries referring to the callstack entry we're reusing */
- cs_index = thr->callstack_top - 1;
- DUK_ASSERT(thr->catchstack_top <= DUK_INT_MAX); /* catchstack limits */
- for (i_stk = (duk_int_t) (thr->catchstack_top - 1); i_stk >= 0; i_stk--) {
- duk_catcher *cat = thr->catchstack + i_stk;
- if (cat->callstack_index != cs_index) {
- /* 'i' is the first entry we'll keep */
- break;
- }
- }
- duk_hthread_catchstack_unwind_norz(thr, i_stk + 1);
-
- /* Unwind the topmost callstack entry before reusing it */
- DUK_ASSERT(thr->callstack_top > 0);
- duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1);
-
- /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- act = thr->callstack + thr->callstack_top;
- thr->callstack_top++;
- thr->callstack_curr = act;
-
- /* Start filling in the activation */
- act->func = func; /* don't want an intermediate exposed state with func == NULL */
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- act->prev_caller = NULL;
-#endif
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
- /* don't want an intermediate exposed state with invalid pc */
- act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- act->prev_line = 0;
-#endif
- DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_HOBJECT_INCREF(thr, func);
- act = thr->callstack_curr; /* side effects (currently none though) */
-#endif
-
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
-#if defined(DUK_USE_TAILCALL)
-#error incorrect options: tail calls enabled with function caller property
-#endif
- /* XXX: this doesn't actually work properly for tail calls, so
- * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- * is in use.
- */
- duk__update_func_caller_prop(thr, func);
- act = thr->callstack_curr;
+ retval = DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+ DUK_UNREF(exc);
+#else
+ } else {
+ /* Error path. */
#endif
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
- act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
- DUK_ACT_FLAG_STRICT | DUK_ACT_FLAG_TAILCALLED :
- DUK_ACT_FLAG_TAILCALLED);
+ DUK_STATS_INC(thr->heap, stats_safecall_throw);
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
- DUK_ASSERT(act->var_env == NULL); /* already NULLed (by unwind) */
- DUK_ASSERT(act->lex_env == NULL); /* already NULLed (by unwind) */
- act->idx_bottom = entry_valstack_bottom_index; /* tail call -> reuse current "frame" */
- DUK_ASSERT(nregs >= 0);
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
+ duk__handle_safe_call_error(thr,
+ entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
#endif
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_byteoff,
+ old_jmpbuf_ptr);
- /*
- * Manipulate valstack so that args are on the current bottom and the
- * previous caller's 'this' binding (which is the value preceding the
- * current bottom) is replaced with the new 'this' binding:
- *
- * [ ... this_old | (crud) func this_new arg1 ... argN ]
- * --> [ ... this_new | arg1 ... argN ]
- *
- * For tail calling to work properly, the valstack bottom must not grow
- * here; otherwise crud would accumulate on the valstack.
- */
-
- tv1 = thr->valstack_bottom - 1;
- tv2 = thr->valstack_bottom + idx_func + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
- DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
-
- for (i_arg = 0; i_arg < idx_args; i_arg++) {
- /* XXX: block removal API primitive */
- /* Note: 'func' is popped from valstack here, but it is
- * already reachable from the activation.
- */
- duk_remove(ctx, 0);
- }
- idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
- idx_args = 0;
-
- /* [ ... this_new | arg1 ... argN ] */
- } else {
- DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
- (long) (thr->callstack_top)));
-
- duk_hthread_callstack_grow(thr);
-
- if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
- DUK_DDD(DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)"));
- } else {
- DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval"));
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack_curr;
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
- act->idx_retval = entry_valstack_bottom_index + idx_func;
+ retval = DUK_EXEC_ERROR;
+ }
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ DUK_STATS_INC(thr->heap, stats_safecall_throw);
+ if (!what) {
+ what = "unknown";
}
-
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- act = thr->callstack + thr->callstack_top;
- thr->callstack_top++;
- thr->callstack_curr = act;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
-
- act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
- DUK_ACT_FLAG_STRICT :
- 0);
- act->func = func;
- act->var_env = NULL;
- act->lex_env = NULL;
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- act->prev_caller = NULL;
-#endif
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
- act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- act->prev_line = 0;
-#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_args;
- DUK_ASSERT(nregs >= 0);
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ DUK_UNREF(exc);
+ duk__handle_safe_call_error(thr,
+ entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
#endif
- DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-
- DUK_HOBJECT_INCREF(thr, func); /* act->func */
-
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- duk__update_func_caller_prop(thr, func);
- act = thr->callstack_curr;
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_byteoff,
+ old_jmpbuf_ptr);
+ retval = DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ DUK_STATS_INC(thr->heap, stats_safecall_throw);
+ try {
+ DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ DUK_UNREF(exc);
+ duk__handle_safe_call_error(thr,
+ entry_act,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
#endif
+ entry_curr_thread,
+ entry_thread_state,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_byteoff,
+ old_jmpbuf_ptr);
+ retval = DUK_EXEC_ERROR;
+ }
}
+#endif
- /* [ ... func this arg1 ... argN ] (not tail call)
- * [ this | arg1 ... argN ] (tail call)
- *
- * idx_args updated to match
- */
-
- /*
- * Environment record creation and 'arguments' object creation.
- * Named function expression name binding is handled by the
- * compiler; the compiled function's parent env will contain
- * the (immutable) binding already.
- *
- * Delayed creation (on demand) is handled in duk_js_var.c.
- */
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
- /* XXX: unify handling with native call. */
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function chain has already been resolved */
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ duk__handle_safe_call_shared_unwind(thr,
+ idx_retbase,
+ num_stack_rets,
+#if defined(DUK_USE_ASSERTIONS)
+ entry_callstack_top,
+#endif
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_ptr_curr_pc);
- if (!DUK_HOBJECT_HAS_NEWENV(func)) {
- /* use existing env (e.g. for non-strict eval); cannot have
- * an own 'arguments' object (but can refer to the existing one)
- */
+ /* Restore preventcount. */
+ thr->callstack_preventcount--;
+ DUK_ASSERT(thr->callstack_preventcount == entry_callstack_preventcount);
- duk__handle_oldenv_for_call(thr, func, act);
- /* No need to re-lookup 'act' at present: no side effects. */
+ /* Final asserts. */
+ DUK_ASSERT(thr->callstack_curr == entry_act);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
+ DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
+ DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
+ DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
+ DUK_ASSERT(thr->state == entry_thread_state);
+ DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
+ DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
+ DUK_ASSERT_LJSTATE_UNSET(thr->heap);
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
- goto env_done;
- }
+ /* Pending side effects. */
+ DUK_REFZERO_CHECK_FAST(thr);
- DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
+ return retval;
+}
- if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
- /* no need to create environment record now; leave as NULL */
- DUK_ASSERT(act->lex_env == NULL);
- DUK_ASSERT(act->var_env == NULL);
- goto env_done;
- }
+/*
+ * Property-based call (foo.noSuch()) error setup: replace target function
+ * on stack top with a specially tagged (hidden Symbol) error which gets
+ * thrown in call handling at the proper spot to follow Ecmascript semantics.
+ */
- /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
- DUK_ASSERT(env != NULL);
+#if defined(DUK_USE_VERBOSE_ERRORS)
+DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key) {
+ const char *str1, *str2, *str3;
+ duk_idx_t entry_top;
- /* [ ... arg1 ... argN envobj ] */
+ entry_top = duk_get_top(thr);
- /* original input stack before nargs/nregs handling must be
- * intact for 'arguments' object
+ /* Must stabilize pointers first. Argument convention is a bit awkward,
+ * it comes from the executor call site where some arguments may not be
+ * on the value stack (consts).
*/
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
-
- /* [ ... arg1 ... argN envobj ] */
+ duk_push_tval(thr, tv_base);
+ duk_push_tval(thr, tv_key);
+ duk_push_tval(thr, tv_targ);
- act = thr->callstack_curr;
- act->lex_env = env;
- act->var_env = env;
- DUK_HOBJECT_INCREF(thr, act->lex_env);
- DUK_HOBJECT_INCREF(thr, act->var_env);
- duk_pop(ctx);
-
- env_done:
- /* [ ... arg1 ... argN ] */
+ DUK_GC_TORTURE(thr->heap);
- /*
- * Setup value stack: clamp to 'nargs', fill up to 'nregs'
+ /* We only push an error, replacing the call target (at idx_func)
+ * with the error to ensure side effects come out correctly:
+ * - Property read
+ * - Call argument evaluation
+ * - Callability check and error thrown.
+ *
+ * A hidden Symbol on the error object pushed here is used by
+ * call handling to figure out the error is to be thrown as is.
+ * It is CRITICAL that the hidden Symbol can never occur on a
+ * user visible object that may get thrown.
*/
- duk__adjust_valstack_and_top(thr,
- num_stack_args,
- idx_args,
- nregs,
- nargs,
- func);
-
- /*
- * Shift to new valstack_bottom.
- */
+#if defined(DUK_USE_PARANOID_ERRORS)
+ str1 = duk_get_type_name(thr, -1);
+ str2 = duk_get_type_name(thr, -2);
+ str3 = duk_get_type_name(thr, -3);
+ duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3);
+#else
+ str1 = duk_push_string_readable(thr, -1);
+ str2 = duk_push_string_readable(thr, -3);
+ str3 = duk_push_string_readable(thr, -5);
+ duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3);
+#endif
- thr->valstack_bottom = thr->valstack_bottom + idx_args;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ duk_push_true(thr);
+ duk_put_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET); /* Marker property, reuse _Target. */
- /*
- * Return to bytecode executor, which will resume execution from
- * the topmost activation.
- */
+ /* [ <nregs> propValue <variable> error ] */
+ duk_replace(thr, entry_top - 1);
+ duk_set_top(thr, entry_top);
- DUK_REFZERO_CHECK_FAST(thr);
- return 1;
+ DUK_ASSERT(!duk_is_callable(thr, -1)); /* Critical so that call handling will throw the error. */
}
+#endif /* DUK_USE_VERBOSE_ERRORS */
+
+/* automatic undefs */
+#undef DUK__AUGMENT_CALL_RELAX_COUNT
/*
* Ecmascript compiler.
*
@@ -62365,8 +63822,8 @@ DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
*
* A few typing notes:
*
- * - duk_regconst_t: unsigned, no marker value for "none"
- * - duk_reg_t: signed, < 0 = none
+ * - duk_regconst_t: signed, highest bit set (< 0) means constant,
+ * some call sites use -1 for "none" (equivalent to constant 0x7fffffff)
* - PC values: duk_int_t, negative values used as markers
*/
@@ -62374,15 +63831,16 @@ DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
/* If highest bit of a register number is set, it refers to a constant instead.
* When interpreted as a signed value, this means const values are always
- * negative (when interpreted as two's complement). For example DUK__ISTEMP()
+ * negative (when interpreted as two's complement). For example DUK__ISREG_TEMP()
* uses this approach to avoid an explicit DUK__ISREG() check (the condition is
* logically "'x' is a register AND 'x' >= temp_first").
*/
#define DUK__CONST_MARKER DUK_REGCONST_CONST_MARKER
-#define DUK__ISREG(x) (((x) & DUK__CONST_MARKER) == 0)
-#define DUK__ISCONST(x) (((x) & DUK__CONST_MARKER) != 0)
#define DUK__REMOVECONST(x) ((x) & ~DUK__CONST_MARKER)
-#define DUK__ISTEMP(comp_ctx,x) ((duk_int32_t) (x) >= (duk_int32_t) ((comp_ctx)->curr_func.temp_first)) /* Avoid DUK__ISREG() check by interpreting as negative value. */
+#define DUK__ISREG(x) ((x) >= 0)
+#define DUK__ISCONST(x) ((x) < 0)
+#define DUK__ISREG_TEMP(comp_ctx,x) ((duk_int32_t) (x) >= (duk_int32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= temp_first && x >= 0 by comparing as signed. */
+#define DUK__ISREG_NOTTEMP(comp_ctx,x) ((duk_uint32_t) (x) < (duk_uint32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= 0 && x < temp_first by interpreting as unsigned. */
#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
@@ -62412,12 +63870,12 @@ DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
- duk__recursion_increase((comp_ctx)); \
+ duk__comp_recursion_increase((comp_ctx)); \
} while (0)
#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
- duk__recursion_decrease((comp_ctx)); \
+ duk__comp_recursion_decrease((comp_ctx)); \
} while (0)
/* Value stack slot limits: these are quite approximate right now, and
@@ -62450,7 +63908,7 @@ DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
/* function helpers */
DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg);
+DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg);
DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
@@ -62464,13 +63922,13 @@ DUK_LOCAL_DECL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t o
DUK_LOCAL_DECL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c);
#if 0 /* unused */
DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
-#endif
DUK_LOCAL_DECL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b);
+#endif
DUK_LOCAL_DECL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc);
DUK_LOCAL_DECL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc);
DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
-DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
-DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
+DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
+DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
@@ -62488,41 +63946,41 @@ DUK_LOCAL_DECL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_iv
DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h);
DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
-DUK_LOCAL_DECL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
-DUK_LOCAL_DECL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next);
+DUK_LOCAL_DECL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
+DUK_LOCAL_DECL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
+DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next);
DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL
duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ispec *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg);
-DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg);
+DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg);
+DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg);
DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
DUK_LOCAL_DECL
duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ivalue *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags);
-DUK_LOCAL_DECL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
+DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
+DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
#endif
DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
/* identifier handling */
-DUK_LOCAL_DECL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
+DUK_LOCAL_DECL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
+DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
/* label handling */
DUK_LOCAL_DECL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id);
DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
DUK_LOCAL_DECL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest);
-DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len);
+DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len);
/* top-down expression parser */
DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
@@ -62536,23 +63994,23 @@ DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_sma
/* convenience helpers */
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
-DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
+DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg);
DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#if 0 /* unused */
DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-DUK_LOCAL_DECL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
+DUK_LOCAL_DECL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#endif
-DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
+DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg);
DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
#if 0 /* unused */
DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
@@ -62564,7 +64022,7 @@ DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalu
DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
/* 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_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_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_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);
@@ -62631,7 +64089,7 @@ DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, d
#define DUK__TOKEN_LBP_BP_MASK 0x1f
#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
-#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* spare */
+#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* unused */
#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
@@ -62747,7 +64205,7 @@ DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
* Misc helpers
*/
-DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) {
DUK_ASSERT(comp_ctx != NULL);
DUK_ASSERT(comp_ctx->recursion_depth >= 0);
if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
@@ -62756,7 +64214,7 @@ DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
comp_ctx->recursion_depth++;
}
-DUK_LOCAL void duk__recursion_decrease(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL void duk__comp_recursion_decrease(duk_compiler_ctx *comp_ctx) {
DUK_ASSERT(comp_ctx != NULL);
DUK_ASSERT(comp_ctx->recursion_depth > 0);
comp_ctx->recursion_depth--;
@@ -62784,10 +64242,10 @@ DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compil
DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bool_t regexp;
- DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
+ DUK_ASSERT_DISABLE(comp_ctx->curr_token.t >= 0); /* unsigned */
+ DUK_ASSERT(comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
/*
* Use current token to decide whether a RegExp can follow.
@@ -62807,7 +64265,7 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e
regexp = 0;
}
- if (expect >= 0 && comp_ctx->curr_token.t != expect) {
+ if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) {
DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
(long) expect, (long) comp_ctx->curr_token.t));
DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
@@ -62815,8 +64273,8 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e
/* make current token the previous; need to fiddle with valstack "backing store" */
DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
- duk_copy(ctx, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
- duk_copy(ctx, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
+ duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
+ duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
/* parse new token */
duk_lexer_parse_js_input_element(&comp_ctx->lex,
@@ -62830,14 +64288,14 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e
(long) comp_ctx->curr_token.t_nores,
(long) comp_ctx->curr_token.start_line,
(long) comp_ctx->curr_token.lineterm,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok11_idx),
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok12_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok11_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok12_idx),
(long) comp_ctx->prev_token.t,
(long) comp_ctx->prev_token.t_nores,
(long) comp_ctx->prev_token.start_line,
(long) comp_ctx->prev_token.lineterm,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok21_idx),
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok22_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok21_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->tok22_idx)));
}
/* advance, expecting current token to be a specific token; parse next token in regexp context */
@@ -62858,10 +64316,9 @@ DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
duk_compiler_func *func = &comp_ctx->curr_func;
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_idx_t entry_top;
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
@@ -62875,46 +64332,46 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
func->h_varmap = NULL;
#endif
- duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
+ duk_require_stack(thr, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
/* code_idx = entry_top + 0 */
- duk_push_array(ctx);
+ duk_push_array(thr);
func->consts_idx = entry_top + 1;
- func->h_consts = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 1);
+ func->h_consts = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 1);
DUK_ASSERT(func->h_consts != NULL);
- duk_push_array(ctx);
+ duk_push_array(thr);
func->funcs_idx = entry_top + 2;
- func->h_funcs = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 2);
+ func->h_funcs = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 2);
DUK_ASSERT(func->h_funcs != NULL);
DUK_ASSERT(func->fnum_next == 0);
- duk_push_array(ctx);
+ duk_push_array(thr);
func->decls_idx = entry_top + 3;
- func->h_decls = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 3);
+ func->h_decls = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 3);
DUK_ASSERT(func->h_decls != NULL);
- duk_push_array(ctx);
+ duk_push_array(thr);
func->labelnames_idx = entry_top + 4;
- func->h_labelnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 4);
+ func->h_labelnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 4);
DUK_ASSERT(func->h_labelnames != NULL);
- duk_push_dynamic_buffer(ctx, 0);
+ duk_push_dynamic_buffer(thr, 0);
func->labelinfos_idx = entry_top + 5;
- func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, entry_top + 5);
+ func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 5);
DUK_ASSERT(func->h_labelinfos != NULL);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
- duk_push_array(ctx);
+ duk_push_array(thr);
func->argnames_idx = entry_top + 6;
- func->h_argnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 6);
+ func->h_argnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 6);
DUK_ASSERT(func->h_argnames != NULL);
- duk_push_bare_object(ctx);
+ duk_push_bare_object(thr);
func->varmap_idx = entry_top + 7;
- func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 7);
+ func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 7);
DUK_ASSERT(func->h_varmap != NULL);
}
@@ -62922,25 +64379,24 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
duk_compiler_func *func = &comp_ctx->curr_func;
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
/* reset bytecode buffer but keep current size; pass 2 will
* require same amount or more.
*/
DUK_BW_RESET_SIZE(thr, &func->bw_code);
- duk_set_length(ctx, func->consts_idx, 0);
+ duk_set_length(thr, func->consts_idx, 0);
/* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
func->fnum_next = 0;
- /* duk_set_length(ctx, func->funcs_idx, 0); */
- duk_set_length(ctx, func->labelnames_idx, 0);
+ /* duk_set_length(thr, func->funcs_idx, 0); */
+ duk_set_length(thr, func->labelnames_idx, 0);
duk_hbuffer_reset(thr, func->h_labelinfos);
/* keep func->h_argnames; it is fixed for all passes */
/* truncated in case pass 3 needed */
- duk_push_bare_object(ctx);
- duk_replace(ctx, func->varmap_idx);
- func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, func->varmap_idx);
+ duk_push_bare_object(thr);
+ duk_replace(thr, func->varmap_idx);
+ func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, func->varmap_idx);
DUK_ASSERT(func->h_varmap != NULL);
}
@@ -62949,7 +64405,6 @@ DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
*/
DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hobject *h_varmap;
duk_hstring *h_key;
duk_tval *tv;
@@ -62958,7 +64413,7 @@ DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
/* [ ... varmap ] */
- h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
+ h_varmap = DUK_GET_HOBJECT_NEGIDX(thr, -1);
DUK_ASSERT(h_varmap != NULL);
ret = 0;
@@ -62989,7 +64444,7 @@ DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
}
}
- duk_compact_m1(ctx);
+ duk_compact_m1(thr);
return ret;
}
@@ -63001,7 +64456,6 @@ DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
duk_compiler_func *func = &comp_ctx->curr_func;
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hcompfunc *h_res;
duk_hbuffer_fixed *h_data;
duk_size_t consts_count;
@@ -63029,7 +64483,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
/* Valstack should suffice here, required on function valstack init */
- h_res = duk_push_hcompfunc(ctx);
+ h_res = duk_push_hcompfunc(thr);
DUK_ASSERT(h_res != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_res) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_res, NULL); /* Function templates are "bare objects". */
@@ -63112,8 +64566,8 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
(long) funcs_count, (long) sizeof(duk_hobject *),
(long) code_size, (long) data_size));
- duk_push_fixed_buffer_nozero(ctx, data_size);
- h_data = (duk_hbuffer_fixed *) duk_known_hbuffer(ctx, -1);
+ duk_push_fixed_buffer_nozero(thr, data_size);
+ h_data = (duk_hbuffer_fixed *) duk_known_hbuffer(thr, -1);
DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
DUK_HEAPHDR_INCREF(thr, h_data);
@@ -63160,7 +64614,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
- duk_pop(ctx); /* 'data' (and everything in it) is reachable through h_res now */
+ duk_pop(thr); /* 'data' (and everything in it) is reachable through h_res now */
/*
* Init non-property result fields
@@ -63217,16 +64671,16 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
if (keep_varmap) {
duk_int_t num_used;
- duk_dup(ctx, func->varmap_idx);
+ duk_dup(thr, func->varmap_idx);
num_used = duk__cleanup_varmap(comp_ctx);
DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
- (duk_tval *) duk_get_tval(ctx, -1), (long) num_used));
+ (duk_tval *) duk_get_tval(thr, -1), (long) num_used));
if (num_used > 0) {
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
} else {
DUK_DD(DUK_DDPRINT("varmap is empty after cleanup -> no need to add"));
- duk_pop(ctx);
+ duk_pop(thr);
}
}
@@ -63242,7 +64696,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
DUK_DD(DUK_DDPRINT("keeping _Formals because debugger support is enabled"));
keep_formals = 1;
#else
- formals_length = duk_get_length(ctx, func->argnames_idx);
+ formals_length = duk_get_length(thr, func->argnames_idx);
if (formals_length != (duk_size_t) h_res->nargs) {
/* Nargs not enough for closure .length: keep _Formals regardless
* of its length. Shouldn't happen in practice at the moment.
@@ -63263,16 +64717,16 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
#endif
if (keep_formals) {
- duk_dup(ctx, func->argnames_idx);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
+ duk_dup(thr, func->argnames_idx);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
}
/* name */
#if defined(DUK_USE_FUNC_NAME_PROPERTY)
if (func->h_name) {
- duk_push_hstring(ctx, func->h_name);
- DUK_DD(DUK_DDPRINT("setting function template .name to %!T", duk_get_tval(ctx, -1)));
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_hstring(thr, func->h_name);
+ DUK_DD(DUK_DDPRINT("setting function template .name to %!T", duk_get_tval(thr, -1)));
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
}
#endif /* DUK_USE_FUNC_NAME_PROPERTY */
@@ -63318,8 +64772,8 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
*/
#if 0
- duk_push_string(ctx, "XXX");
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_string(thr, "XXX");
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
#endif
}
#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
@@ -63333,7 +64787,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
/* XXX: if assertions enabled, walk through all valid PCs
* and check line mapping.
@@ -63348,19 +64802,19 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
* Source filename (or equivalent), for identifying thrown errors.
*/
- duk_push_hstring(ctx, comp_ctx->h_filename);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_hstring(thr, comp_ctx->h_filename);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
}
#endif
DUK_DD(DUK_DDPRINT("converted function: %!ixT",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/*
* Compact the function template.
*/
- duk_compact_m1(ctx);
+ duk_compact_m1(thr);
/*
* Debug dumping
@@ -63371,7 +64825,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
duk_hcompfunc *h;
duk_instr_t *p, *p_start, *p_end;
- h = (duk_hcompfunc *) duk_get_hobject(ctx, -1);
+ h = (duk_hcompfunc *) duk_get_hobject(thr, -1);
p_start = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, h);
p_end = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, h);
@@ -63485,7 +64939,7 @@ DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
instr->ins = ins;
#if defined(DUK_USE_PC2LINE)
- instr->line = line;
+ instr->line = (duk_uint32_t) line;
#endif
#if defined(DUK_USE_DEBUGGER_SUPPORT)
if (line < comp_ctx->curr_func.min_line) {
@@ -63554,7 +65008,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
duk_int_t b_out = -1;
duk_int_t c_out = -1;
duk_int_t tmp;
- duk_small_int_t op = op_flags & 0xff;
+ duk_small_uint_t op = op_flags & 0xffU;
DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
(unsigned long) op_flags, (long) a, (long) b, (long) c));
@@ -63568,6 +65022,9 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
+ DUK_ASSERT(DUK__ISREG(a));
+ DUK_ASSERT(b != -1); /* Not 'none'. */
+ DUK_ASSERT(c != -1); /* Not 'none'. */
/* Input shuffling happens before the actual operation, while output
* shuffling happens afterwards. Output shuffling decisions are still
@@ -63599,7 +65056,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
* consecutive.
*/
DUK_ASSERT((comp_ctx->curr_func.shuffle1 == 0 && comp_ctx->curr_func.shuffle2 == 0) ||
- comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1);
+ (comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1));
if (op == DUK_OP_CSVAR) {
/* For CSVAR the limit is one smaller because output shuffle
* must be able to express 'a + 1' in BC.
@@ -63617,7 +65074,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
/* Slot B: reg/const support, mapped to bit 0 of opcode. */
- if (b & DUK__CONST_MARKER) {
+ if ((b & DUK__CONST_MARKER) != 0) {
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
b = b & ~DUK__CONST_MARKER;
@@ -63687,7 +65144,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
/* Slot C: reg/const support, mapped to bit 1 of opcode. */
- if (c & DUK__CONST_MARKER) {
+ if ((c & DUK__CONST_MARKER) != 0) {
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
c = c & ~DUK__CONST_MARKER;
@@ -63743,11 +65200,11 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
/* Main operation */
- DUK_ASSERT_DISABLE(a >= DUK_BC_A_MIN); /* unsigned */
+ DUK_ASSERT(a >= DUK_BC_A_MIN);
DUK_ASSERT(a <= DUK_BC_A_MAX);
- DUK_ASSERT_DISABLE(b >= DUK_BC_B_MIN); /* unsigned */
+ DUK_ASSERT(b >= DUK_BC_B_MIN);
DUK_ASSERT(b <= DUK_BC_B_MAX);
- DUK_ASSERT_DISABLE(c >= DUK_BC_C_MIN); /* unsigned */
+ DUK_ASSERT(c >= DUK_BC_C_MIN);
DUK_ASSERT(c <= DUK_BC_C_MAX);
ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
@@ -63832,23 +65289,26 @@ DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
}
#endif
+#if 0 /* unused */
DUK_LOCAL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b) {
#if defined(DUK_USE_SHUFFLE_TORTURE)
op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C;
#endif
duk__emit_a_b_c(comp_ctx, op_flags, 0, b, 0);
}
+#endif
DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc) {
duk_instr_t ins;
duk_int_t tmp;
/* allow caller to give a const number with the DUK__CONST_MARKER */
+ DUK_ASSERT(bc != -1); /* Not 'none'. */
bc = bc & (~DUK__CONST_MARKER);
DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
- DUK_ASSERT_DISABLE(bc >= DUK_BC_BC_MIN); /* unsigned */
+ DUK_ASSERT(bc >= DUK_BC_BC_MIN);
DUK_ASSERT(bc <= DUK_BC_BC_MAX);
DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
@@ -63868,6 +65328,13 @@ DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_fl
duk__emit(comp_ctx, ins);
} else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
goto error_outofregs;
+ } else if ((op_flags & 0xf0U) == DUK_OP_CALL0) {
+ comp_ctx->curr_func.needs_shuffle = 1;
+ tmp = comp_ctx->curr_func.shuffle1;
+ duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
+ op_flags |= DUK_BC_CALL_FLAG_INDIRECT;
+ ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
+ duk__emit(comp_ctx, ins);
} else if (a <= DUK_BC_BC_MAX) {
comp_ctx->curr_func.needs_shuffle = 1;
tmp = comp_ctx->curr_func.shuffle1;
@@ -63903,6 +65370,7 @@ DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, du
DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */
DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
+ DUK_ASSERT(abc != -1); /* Not 'none'. */
if (abc <= DUK_BC_ABC_MAX) {
;
@@ -63921,7 +65389,7 @@ DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, du
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
}
-DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
+DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
/* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
* would only shuffle once (instead of twice). The current code works
* though, and has a smaller compiler footprint.
@@ -63942,7 +65410,7 @@ DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_reg_t re
}
}
-DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
+DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
}
@@ -63950,11 +65418,11 @@ DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, d
/* Used by duk__emit*() calls so that we don't shuffle the loadints that
* are needed to handle indirect opcodes.
*/
-DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
+DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
}
#else
-DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
+DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
/* When torture not enabled, can just use the same helper because
* 'reg' won't get spilled.
*/
@@ -63992,7 +65460,8 @@ DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump
duk_compiler_instr *instr;
duk_size_t offset;
- offset = jump_pc * sizeof(duk_compiler_instr),
+ DUK_ASSERT(jump_pc >= 0);
+ offset = (duk_size_t) jump_pc * sizeof(duk_compiler_instr);
instr = (duk_compiler_instr *) (void *)
DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
&comp_ctx->curr_func.bw_code,
@@ -64004,7 +65473,7 @@ DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump
#endif
instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
#if defined(DUK_USE_PC2LINE)
- instr->line = line;
+ instr->line = (duk_uint32_t) line;
#endif
DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
@@ -64051,7 +65520,7 @@ DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_p
DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags) {
duk_compiler_instr *instr;
- DUK_ASSERT((reg_catch & DUK__CONST_MARKER) == 0);
+ DUK_ASSERT(DUK__ISREG(reg_catch));
instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
@@ -64138,7 +65607,7 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
continue;
}
- target_pc1 = i + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
+ target_pc1 = i + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
DUK_ASSERT(target_pc1 >= 0);
DUK_ASSERT(target_pc1 < n);
@@ -64153,7 +65622,7 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
continue;
}
- target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
+ target_pc2 = target_pc1 + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
(long) i, (long) target_pc1, (long) target_pc2));
@@ -64179,11 +65648,14 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
* is not needed, the forced_reg argument suffices and generates better
* code (it is checked as it is used).
*/
+/* XXX: DUK__IVAL_FLAG_REQUIRE_SHORT is passed but not currently implemented
+ * by ispec/ivalue operations.
+ */
#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
-/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
+/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(thr,x) */
#if 0 /* enable manually for dumping */
#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
@@ -64192,7 +65664,7 @@ DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
(long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->valstack_idx)));
+ duk_get_tval(comp_ctx->thr, x->valstack_idx)));
}
DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
@@ -64200,9 +65672,9 @@ DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
"x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
(long) x->t, (long) x->op,
(long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->x1.valstack_idx),
+ duk_get_tval(comp_ctx->thr, x->x1.valstack_idx),
(long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->x2.valstack_idx)));
+ duk_get_tval(comp_ctx->thr, x->x2.valstack_idx)));
}
#else
#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
@@ -64212,50 +65684,46 @@ DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
DUK_LOCAL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst) {
x->t = DUK_IVAL_PLAIN;
x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) regconst;
+ x->x1.regconst = regconst;
}
DUK_LOCAL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
x->t = DUK_IVAL_PLAIN;
x->x1.t = DUK_ISPEC_VALUE;
- duk_replace((duk_context *) comp_ctx->thr, x->x1.valstack_idx);
+ duk_replace(comp_ctx->thr, x->x1.valstack_idx);
}
DUK_LOCAL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
x->t = DUK_IVAL_VAR;
x->x1.t = DUK_ISPEC_VALUE;
- duk_replace((duk_context *) comp_ctx->thr, x->x1.valstack_idx);
+ duk_replace(comp_ctx->thr, x->x1.valstack_idx);
}
DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h) {
DUK_ASSERT(h != NULL);
- duk_push_hstring((duk_context *) comp_ctx->thr, h);
+ duk_push_hstring(comp_ctx->thr, h);
duk__ivalue_var_fromstack(comp_ctx, x);
}
DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
- duk_context *ctx = (duk_context *) comp_ctx->thr;
-
dst->t = src->t;
dst->regconst = src->regconst;
- duk_copy(ctx, src->valstack_idx, dst->valstack_idx);
+ duk_copy(comp_ctx->thr, src->valstack_idx, dst->valstack_idx);
}
DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
- duk_context *ctx = (duk_context *) comp_ctx->thr;
-
dst->t = src->t;
dst->op = src->op;
dst->x1.t = src->x1.t;
dst->x1.regconst = src->x1.regconst;
dst->x2.t = src->x2.t;
dst->x2.regconst = src->x2.regconst;
- duk_copy(ctx, src->x1.valstack_idx, dst->x1.valstack_idx);
- duk_copy(ctx, src->x2.valstack_idx, dst->x2.valstack_idx);
+ duk_copy(comp_ctx->thr, src->x1.valstack_idx, dst->x1.valstack_idx);
+ duk_copy(comp_ctx->thr, src->x2.valstack_idx, dst->x2.valstack_idx);
}
-DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
- duk_reg_t res;
+DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
+ duk_regconst_t res;
res = comp_ctx->curr_func.temp_next;
comp_ctx->curr_func.temp_next += num;
@@ -64272,11 +65740,11 @@ DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t
return res;
}
-DUK_LOCAL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
return duk__alloctemps(comp_ctx, 1);
}
-DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next) {
+DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next) {
comp_ctx->curr_func.temp_next = temp_next;
if (temp_next > comp_ctx->curr_func.temp_max) {
comp_ctx->curr_func.temp_max = temp_next;
@@ -64286,14 +65754,13 @@ DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_
/* get const for value at valstack top */
DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_compiler_func *f = &comp_ctx->curr_func;
duk_tval *tv1;
duk_int_t i, n, n_check;
- n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
+ n = (duk_int_t) duk_get_length(thr, f->consts_idx);
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(tv1 != NULL);
#if defined(DUK_USE_FASTINT)
@@ -64315,8 +65782,8 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
if (duk_js_samevalue(tv1, tv2)) {
DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
(duk_tval *) tv1, (long) i));
- duk_pop(ctx);
- return (duk_regconst_t) (i | DUK__CONST_MARKER);
+ duk_pop(thr);
+ return (duk_regconst_t) i | (duk_regconst_t) DUK__CONST_MARKER;
}
}
@@ -64326,20 +65793,19 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
(duk_tval *) tv1, (long) n));
- (void) duk_put_prop_index(ctx, f->consts_idx, n); /* invalidates tv1, tv2 */
- return (duk_regconst_t) (n | DUK__CONST_MARKER);
+ (void) duk_put_prop_index(thr, f->consts_idx, (duk_uarridx_t) n); /* invalidates tv1, tv2 */
+ return (duk_regconst_t) n | (duk_regconst_t) DUK__CONST_MARKER;
}
DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_regconst_t rc) {
#if defined(DUK_USE_REFERENCE_COUNTING)
- duk_context *ctx = (duk_context *) comp_ctx->thr;
duk_compiler_func *f = &comp_ctx->curr_func;
duk_bool_t ret;
DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */
- (void) duk_get_prop_index(ctx, f->consts_idx, (duk_uarridx_t) rc);
- ret = !duk_is_number(ctx, -1); /* now only number/string, so conservative check */
- duk_pop(ctx);
+ (void) duk_get_prop_index(comp_ctx->thr, f->consts_idx, (duk_uarridx_t) rc);
+ ret = !duk_is_number(comp_ctx->thr, -1); /* now only number/string, so conservative check */
+ duk_pop(comp_ctx->thr);
return ret;
#else
DUK_UNREF(comp_ctx);
@@ -64368,16 +65834,15 @@ DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_r
DUK_LOCAL
duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ispec *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
"forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
(long) x->t,
(long) x->regconst,
- (duk_tval *) duk_get_tval(ctx, x->valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->valstack_idx),
(long) forced_reg,
(unsigned long) flags,
(long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
@@ -64388,7 +65853,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
case DUK_ISPEC_VALUE: {
duk_tval *tv;
- tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
+ tv = DUK_GET_TVAL_POSIDX(thr, x->valstack_idx);
DUK_ASSERT(tv != NULL);
switch (DUK_TVAL_GET_TAG(tv)) {
@@ -64397,21 +65862,21 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
* values can occur during compilation as a result of e.g.
* the 'void' operator.
*/
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
+ duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
+ duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, dest);
+ return dest;
}
case DUK_TAG_NULL: {
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_bc(comp_ctx, DUK_OP_LDNULL, (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
+ duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
+ duk__emit_bc(comp_ctx, DUK_OP_LDNULL, dest);
+ return dest;
}
case DUK_TAG_BOOLEAN: {
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
+ duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
duk__emit_bc(comp_ctx,
(DUK_TVAL_GET_BOOLEAN(tv) ? DUK_OP_LDTRUE : DUK_OP_LDFALSE),
- (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
+ dest);
+ return dest;
}
case DUK_TAG_POINTER: {
DUK_UNREACHABLE();
@@ -64419,7 +65884,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
case DUK_TAG_STRING: {
duk_hstring *h;
- duk_reg_t dest;
+ duk_regconst_t dest;
duk_regconst_t constidx;
h = DUK_TVAL_GET_STRING(tv);
@@ -64434,7 +65899,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
/* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
}
#endif
- duk_dup(ctx, x->valstack_idx);
+ duk_dup(thr, x->valstack_idx);
constidx = duk__getconst(comp_ctx);
if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
@@ -64442,8 +65907,8 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
- return (duk_regconst_t) dest;
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
+ return dest;
}
case DUK_TAG_OBJECT: {
DUK_UNREACHABLE();
@@ -64462,7 +65927,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
#endif
default: {
/* number */
- duk_reg_t dest;
+ duk_regconst_t dest;
duk_regconst_t constidx;
duk_double_t dval;
duk_int32_t ival;
@@ -64481,50 +65946,50 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
if (duk_is_whole_get_int32_nonegzero(dval, &ival)) {
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
duk__emit_load_int32(comp_ctx, dest, ival);
- return (duk_regconst_t) dest;
+ return dest;
}
}
- duk_dup(ctx, x->valstack_idx);
+ duk_dup(thr, x->valstack_idx);
constidx = duk__getconst(comp_ctx);
if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
return constidx;
} else {
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
- return (duk_regconst_t) dest;
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
+ return dest;
}
}
} /* end switch */
}
case DUK_ISPEC_REGCONST: {
if (forced_reg >= 0) {
- if (x->regconst & DUK__CONST_MARKER) {
+ if (DUK__ISCONST(x->regconst)) {
duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
- } else if (x->regconst != (duk_regconst_t) forced_reg) {
+ } else if (x->regconst != forced_reg) {
duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
} else {
; /* already in correct reg */
}
- return (duk_regconst_t) forced_reg;
+ return forced_reg;
}
DUK_ASSERT(forced_reg < 0);
- if (x->regconst & DUK__CONST_MARKER) {
+ if (DUK__ISCONST(x->regconst)) {
if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
- duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, x->regconst);
- return (duk_regconst_t) dest;
+ duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst);
+ return dest;
}
return x->regconst;
}
- DUK_ASSERT(forced_reg < 0 && !(x->regconst & DUK__CONST_MARKER));
- if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISTEMP(comp_ctx, x->regconst)) {
- duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, (duk_regconst_t) dest, x->regconst);
- return (duk_regconst_t) dest;
+ DUK_ASSERT(forced_reg < 0 && !DUK__ISCONST(x->regconst));
+ if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISREG_TEMP(comp_ctx, x->regconst)) {
+ duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
+ duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst);
+ return dest;
}
return x->regconst;
}
@@ -64537,7 +66002,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
return 0;
}
-DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) {
DUK_ASSERT(forced_reg >= 0);
(void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
}
@@ -64547,17 +66012,16 @@ DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x,
* The duk_ivalue argument ('x') is converted into a plain value as a
* side effect.
*/
-DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
"forced_reg=%ld",
(long) x->t, (long) x->op,
(long) x->x1.t, (long) x->x1.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
(long) x->x2.t, (long) x->x2.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
(long) forced_reg));
switch (x->t) {
@@ -64568,7 +66032,7 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
case DUK_IVAL_ARITH: {
duk_regconst_t arg1;
duk_regconst_t arg2;
- duk_reg_t dest;
+ duk_regconst_t dest;
duk_tval *tv1;
duk_tval *tv2;
@@ -64577,8 +66041,8 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
/* inline arithmetic check for constant values */
/* XXX: use the exactly same arithmetic function here as in executor */
if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
- tv1 = DUK_GET_TVAL_POSIDX(ctx, x->x1.valstack_idx);
- tv2 = DUK_GET_TVAL_POSIDX(ctx, x->x2.valstack_idx);
+ tv1 = DUK_GET_TVAL_POSIDX(thr, x->x1.valstack_idx);
+ tv2 = DUK_GET_TVAL_POSIDX(thr, x->x2.valstack_idx);
DUK_ASSERT(tv1 != NULL);
DUK_ASSERT(tv2 != NULL);
@@ -64637,10 +66101,10 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
/* Inline string concatenation. No need to check for
* symbols, as all inputs are valid Ecmascript strings.
*/
- duk_dup(ctx, x->x1.valstack_idx);
- duk_dup(ctx, x->x2.valstack_idx);
- duk_concat(ctx, 2);
- duk_replace(ctx, x->x1.valstack_idx);
+ duk_dup(thr, x->x1.valstack_idx);
+ duk_dup(thr, x->x2.valstack_idx);
+ duk_concat(thr, 2);
+ duk_replace(thr, x->x1.valstack_idx);
x->t = DUK_IVAL_PLAIN;
DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
return;
@@ -64655,25 +66119,25 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
*/
if (forced_reg >= 0) {
dest = forced_reg;
- } else if (DUK__ISTEMP(comp_ctx, arg1)) {
- dest = (duk_reg_t) arg1;
- } else if (DUK__ISTEMP(comp_ctx, arg2)) {
- dest = (duk_reg_t) arg2;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
+ dest = arg1;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
+ dest = arg2;
} else {
dest = DUK__ALLOCTEMP(comp_ctx);
}
DUK_ASSERT(DUK__ISREG(dest));
- duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, (duk_regconst_t) dest, arg1, arg2);
+ duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, dest, arg1, arg2);
- duk__ivalue_regconst(x, (duk_regconst_t) dest);
+ duk__ivalue_regconst(x, dest);
return;
}
case DUK_IVAL_PROP: {
/* XXX: very similar to DUK_IVAL_ARITH - merge? */
duk_regconst_t arg1;
duk_regconst_t arg2;
- duk_reg_t dest;
+ duk_regconst_t dest;
/* Need a short reg/const, does not have to be a mutable temp. */
arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
@@ -64690,38 +66154,38 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x
if (forced_reg >= 0) {
dest = forced_reg;
- } else if (DUK__ISTEMP(comp_ctx, arg1)) {
- dest = (duk_reg_t) arg1;
- } else if (DUK__ISTEMP(comp_ctx, arg2)) {
- dest = (duk_reg_t) arg2;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
+ dest = arg1;
+ } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
+ dest = arg2;
} else {
dest = DUK__ALLOCTEMP(comp_ctx);
}
duk__emit_a_b_c(comp_ctx,
DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) dest,
+ dest,
arg1,
arg2);
- duk__ivalue_regconst(x, (duk_regconst_t) dest);
+ duk__ivalue_regconst(x, dest);
return;
}
case DUK_IVAL_VAR: {
/* x1 must be a string */
- duk_reg_t dest;
- duk_reg_t reg_varbind;
+ duk_regconst_t dest;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
- duk_dup(ctx, x->x1.valstack_idx);
+ duk_dup(thr, x->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- duk__ivalue_regconst(x, (duk_regconst_t) reg_varbind);
+ duk__ivalue_regconst(x, reg_varbind);
} else {
dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, (duk_regconst_t) dest, rc_varname);
- duk__ivalue_regconst(x, (duk_regconst_t) dest);
+ duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, dest, rc_varname);
+ duk__ivalue_regconst(x, dest);
}
return;
}
@@ -64743,7 +66207,7 @@ DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- duk_reg_t temp;
+ duk_regconst_t temp;
/* If duk__ivalue_toplain_raw() allocates a temp, forget it and
* restore next temp state.
@@ -64762,21 +66226,19 @@ DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue
DUK_LOCAL
duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
duk_ivalue *x,
- duk_reg_t forced_reg,
+ duk_regconst_t forced_reg,
duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_regconst_t reg;
DUK_UNREF(thr);
- DUK_UNREF(ctx);
DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
"forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
(long) x->t, (long) x->op,
(long) x->x1.t, (long) x->x1.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
(long) x->x2.t, (long) x->x2.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
+ (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
(long) forced_reg,
(unsigned long) flags,
(long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
@@ -64789,17 +66251,17 @@ duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
/* then to a register */
reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
- duk__ivalue_regconst(x, (duk_regconst_t) reg);
+ duk__ivalue_regconst(x, reg);
return reg;
}
-DUK_LOCAL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
+DUK_LOCAL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
}
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
+DUK_LOCAL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
}
#endif
@@ -64829,20 +66291,19 @@ DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk
* Identifier handling
*/
-DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
+DUK_LOCAL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h_varname;
- duk_reg_t ret;
+ duk_regconst_t ret;
DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
/*
* Special name handling
*/
- h_varname = duk_known_hstring(ctx, -1);
+ h_varname = duk_known_hstring(thr, -1);
if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
@@ -64867,12 +66328,12 @@ DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_c
* name will use slow path.
*/
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- if (duk_is_number(ctx, -1)) {
- ret = duk_to_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
+ if (duk_is_number(thr, -1)) {
+ ret = duk_to_int(thr, -1);
+ duk_pop(thr);
} else {
- duk_pop(ctx);
+ duk_pop(thr);
if (comp_ctx->curr_func.catch_depth > 0 || comp_ctx->curr_func.with_depth > 0) {
DUK_DDD(DUK_DDDPRINT("slow path access from inside a try-catch or with needs _Varmap"));
goto slow_path_own;
@@ -64893,14 +66354,14 @@ DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_c
DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, not own variable"));
comp_ctx->curr_func.id_access_slow = 1;
- return (duk_reg_t) -1;
+ return (duk_regconst_t) -1;
slow_path_own:
DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, may be own variable"));
comp_ctx->curr_func.id_access_slow = 1;
comp_ctx->curr_func.id_access_slow_own = 1;
- return (duk_reg_t) -1;
+ return (duk_regconst_t) -1;
}
/* Lookup an identifier name in the current varmap, indicating whether the
@@ -64911,21 +66372,20 @@ DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_c
* return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
* is unsigned and doesn't have a "unused" / none value.
*/
-DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
+DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
/* [ ... varname ] */
- duk_dup_top(ctx);
+ duk_dup_top(thr);
reg_varbind = duk__lookup_active_register_binding(comp_ctx);
if (reg_varbind >= 0) {
*out_reg_varbind = reg_varbind;
*out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
- duk_pop(ctx);
+ duk_pop(thr);
return 1;
} else {
rc_varname = duk__getconst(comp_ctx);
@@ -64945,7 +66405,6 @@ DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_
DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_size_t n;
duk_size_t new_size;
duk_uint8_t *p;
@@ -64973,13 +66432,13 @@ DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label,
}
}
- duk_push_hstring(ctx, h_label);
+ duk_push_hstring(thr, h_label);
DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */
- (void) duk_put_prop_index(ctx, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
+ (void) duk_put_prop_index(thr, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
new_size = (n + 1) * sizeof(duk_labelinfo);
duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
- /* XXX: spare handling, slow now */
+ /* XXX: slack handling, slow now */
/* relookup after possible realloc */
p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
@@ -65050,7 +66509,6 @@ DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t lab
/* XXX: awkward, especially the bunch of separate output values -> output struct? */
DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_uint8_t *p;
duk_labelinfo *li_start, *li_end, *li;
duk_bool_t match = 0;
@@ -65058,7 +66516,7 @@ DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring
DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
(duk_heaphdr *) h_label, (long) is_break));
- DUK_UNREF(ctx);
+ DUK_UNREF(thr);
p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
li_start = (duk_labelinfo *) (void *) p;
@@ -65121,12 +66579,11 @@ DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring
*out_is_closest = (li == li_end - 1);
}
-DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len) {
+DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_set_length(ctx, comp_ctx->curr_func.labelnames_idx, (duk_size_t) len);
- duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * (duk_size_t) len);
+ duk_set_length(thr, comp_ctx->curr_func.labelnames_idx, len);
+ duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * len);
}
/*
@@ -65144,15 +66601,19 @@ DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t
DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_reg_t reg_obj; /* result reg */
- duk_reg_t reg_temp; /* temp reg */
- duk_reg_t temp_start; /* temp reg value for start of loop */
+ duk_regconst_t reg_obj; /* result reg */
+ duk_regconst_t reg_temp; /* temp reg */
+ duk_regconst_t temp_start; /* temp reg value for start of loop */
duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */
duk_small_uint_t num_values; /* number of values in current MPUTARR set */
duk_uarridx_t curr_idx; /* current (next) array index */
duk_uarridx_t start_idx; /* start array index of current MPUTARR set */
duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */
duk_bool_t require_comma; /* next loop requires a comma */
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_int_t pc_newarr;
+ duk_compiler_instr *instr;
+#endif
/* DUK_TOK_LBRACKET already eaten, current token is right after that */
DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
@@ -65160,6 +66621,9 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
reg_obj = DUK__ALLOCTEMP(comp_ctx);
+#if !defined(DUK_USE_PREFER_SIZE)
+ pc_newarr = duk__get_current_pc(comp_ctx);
+#endif
duk__emit_bc(comp_ctx, DUK_OP_NEWARR, reg_obj); /* XXX: patch initial size hint afterwards? */
temp_start = DUK__GETTEMP(comp_ctx);
@@ -65250,8 +66714,8 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
DUK_OP_MPUTARR |
DUK__EMIT_FLAG_NO_SHUFFLE_C |
DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
- (duk_regconst_t) temp_start,
+ reg_obj,
+ temp_start,
(duk_regconst_t) (num_values + 1));
init_idx = start_idx + num_values;
@@ -65259,6 +66723,14 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
}
}
+ /* Update initil size for NEWARR, doesn't need to be exact and is
+ * capped at A field limit.
+ */
+#if !defined(DUK_USE_PREFER_SIZE)
+ instr = duk__get_instr_ptr(comp_ctx, pc_newarr);
+ instr->ins |= DUK_ENC_OP_A(0, curr_idx > DUK_BC_A_MAX ? DUK_BC_A_MAX : curr_idx);
+#endif
+
DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
duk__advance(comp_ctx);
@@ -65273,13 +66745,13 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
duk__emit_a_bc(comp_ctx,
DUK_OP_SETALEN | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
- (duk_regconst_t) reg_temp);
+ reg_obj,
+ reg_temp);
}
DUK__SETTEMP(comp_ctx, temp_start);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_obj);
+ duk__ivalue_regconst(res, reg_obj);
return;
syntax_error:
@@ -65287,9 +66759,10 @@ DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *re
}
typedef struct {
- duk_reg_t reg_obj;
- duk_reg_t temp_start;
+ duk_regconst_t reg_obj;
+ duk_regconst_t temp_start;
duk_small_uint_t num_pairs;
+ duk_small_uint_t num_total_pairs;
} duk__objlit_state;
DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_state *st) {
@@ -65309,20 +66782,21 @@ DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_st
DUK__EMIT_FLAG_A_IS_SOURCE,
st->reg_obj,
st->temp_start,
- st->num_pairs * 2);
+ (duk_regconst_t) (st->num_pairs * 2));
+ st->num_total_pairs += st->num_pairs;
st->num_pairs = 0;
}
DUK__SETTEMP(comp_ctx, st->temp_start);
}
-DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_reg_t reg_temp) {
+DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_regconst_t reg_temp) {
if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t_nores == DUK_TOK_STRING) {
/* same handling for identifiers and strings */
DUK_ASSERT(tok->str1 != NULL);
- duk_push_hstring((duk_context *) comp_ctx->thr, tok->str1);
+ duk_push_hstring(comp_ctx->thr, tok->str1);
} else if (tok->t == DUK_TOK_NUMBER) {
/* numbers can be loaded as numbers and coerced on the fly */
- duk_push_number((duk_context *) comp_ctx->thr, tok->num);
+ duk_push_number(comp_ctx->thr, tok->num);
} else {
return 1; /* error */
}
@@ -65337,10 +66811,14 @@ DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue
DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
duk__objlit_state st;
- duk_reg_t reg_temp; /* temp reg */
+ duk_regconst_t reg_temp; /* temp reg */
duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */
duk_bool_t first; /* first value: comma must not precede the value */
duk_bool_t is_set, is_get; /* temps */
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_int_t pc_newobj;
+ duk_compiler_instr *instr;
+#endif
DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
@@ -65349,8 +66827,12 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
st.reg_obj = DUK__ALLOCTEMP(comp_ctx); /* target object */
st.temp_start = DUK__GETTEMP(comp_ctx); /* start of MPUTOBJ argument list */
st.num_pairs = 0; /* number of key/value pairs emitted for current MPUTOBJ set */
+ st.num_total_pairs = 0; /* number of key/value pairs emitted overall */
- duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj); /* XXX: patch initial size hint afterwards? */
+#if !defined(DUK_USE_PREFER_SIZE)
+ pc_newobj = duk__get_current_pc(comp_ctx);
+#endif
+ duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj);
/*
* Emit initializers in sets of maximum max_init_pairs keys.
@@ -65416,7 +66898,7 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
/* Reset temp register state and reserve reg_temp and
* reg_temp + 1 for handling the current property.
*/
- DUK__SETTEMP(comp_ctx, st.temp_start + 2 * st.num_pairs);
+ DUK__SETTEMP(comp_ctx, st.temp_start + 2 * (duk_regconst_t) st.num_pairs);
reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
/* NOTE: "get" and "set" are not officially ReservedWords and the lexer
@@ -65446,7 +66928,7 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) (st.temp_start + 1),
+ st.temp_start + 1,
(duk_regconst_t) fnum);
/* Slot C is used in a non-standard fashion (range of regs),
@@ -65494,7 +66976,7 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) (reg_temp + 1),
+ reg_temp + 1,
(duk_regconst_t) fnum);
st.num_pairs++;
@@ -65538,10 +67020,21 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
DUK_ASSERT(st.num_pairs == 0);
DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start);
+ /* Update initial size for NEWOBJ. The init size doesn't need to be
+ * exact as the purpose is just to avoid object resizes in common
+ * cases. The size is capped to field A limit, and will be too high
+ * if the object literal contains duplicate keys (this is harmless but
+ * increases memory traffic if the object is compacted later on).
+ */
+#if !defined(DUK_USE_PREFER_SIZE)
+ instr = duk__get_instr_ptr(comp_ctx, pc_newobj);
+ instr->ins |= DUK_ENC_OP_A(0, st.num_total_pairs > DUK_BC_A_MAX ? DUK_BC_A_MAX : st.num_total_pairs);
+#endif
+
DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
duk__advance(comp_ctx);
- duk__ivalue_regconst(res, (duk_regconst_t) st.reg_obj);
+ duk__ivalue_regconst(res, st.reg_obj);
return;
syntax_error:
@@ -65554,7 +67047,7 @@ DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *r
*/
DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_int_t nargs = 0;
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
/* Note: expect that caller has already eaten the left paren */
@@ -65604,10 +67097,9 @@ DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_token *tk;
- duk_reg_t temp_at_entry;
- duk_small_int_t tok;
+ duk_regconst_t temp_at_entry;
+ duk_small_uint_t tok;
duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
/*
@@ -65633,12 +67125,12 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
/* PRIMARY EXPRESSIONS */
case DUK_TOK_THIS: {
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_bc(comp_ctx,
DUK_OP_LDTHIS,
- (duk_regconst_t) reg_temp);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
return;
}
case DUK_TOK_IDENTIFIER: {
@@ -65646,29 +67138,29 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
return;
}
case DUK_TOK_NULL: {
- duk_push_null(ctx);
+ duk_push_null(thr);
goto plain_value;
}
case DUK_TOK_TRUE: {
- duk_push_true(ctx);
+ duk_push_true(thr);
goto plain_value;
}
case DUK_TOK_FALSE: {
- duk_push_false(ctx);
+ duk_push_false(thr);
goto plain_value;
}
case DUK_TOK_NUMBER: {
- duk_push_number(ctx, tk->num);
+ duk_push_number(thr, tk->num);
goto plain_value;
}
case DUK_TOK_STRING: {
DUK_ASSERT(tk->str1 != NULL);
- duk_push_hstring(ctx, tk->str1);
+ duk_push_hstring(thr, tk->str1);
goto plain_value;
}
case DUK_TOK_REGEXP: {
#if defined(DUK_USE_REGEXP_SUPPORT)
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
duk_regconst_t rc_re_bytecode; /* const */
duk_regconst_t rc_re_source; /* const */
@@ -65680,8 +67172,8 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
(duk_heaphdr *) tk->str2));
reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_push_hstring(ctx, tk->str1);
- duk_push_hstring(ctx, tk->str2);
+ duk_push_hstring(thr, tk->str1);
+ duk_push_hstring(thr, tk->str2);
/* [ ... pattern flags ] */
@@ -65694,11 +67186,11 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk__emit_a_b_c(comp_ctx,
DUK_OP_REGEXP | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_temp /*a*/,
+ reg_temp /*a*/,
rc_re_bytecode /*b*/,
rc_re_source /*c*/);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
return;
#else /* DUK_USE_REGEXP_SUPPORT */
goto syntax_error;
@@ -65746,14 +67238,41 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
* and testcases/test-dev-new.js for a bunch of documented tests.
*/
- duk_reg_t reg_target;
+ duk_regconst_t reg_target;
duk_int_t nargs;
DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
- reg_target = DUK__ALLOCTEMP(comp_ctx);
+ reg_target = DUK__ALLOCTEMPS(comp_ctx, 2);
+
+#if defined(DUK_USE_ES6)
+ if (comp_ctx->curr_token.t == DUK_TOK_PERIOD) {
+ /* new.target */
+ DUK_DDD(DUK_DDDPRINT("new.target"));
+ duk__advance(comp_ctx);
+ if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER ||
+ !duk_hstring_equals_ascii_cstring(comp_ctx->curr_token.str1, "target")) {
+ goto syntax_error_newtarget;
+ }
+ if (comp_ctx->curr_func.is_global) {
+ goto syntax_error_newtarget;
+ }
+ duk__advance(comp_ctx);
+ duk__emit_bc(comp_ctx,
+ DUK_OP_NEWTARGET,
+ reg_target);
+ duk__ivalue_regconst(res, reg_target);
+ return;
+ }
+#endif /* DUK_USE_ES6 */
+
duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
- DUK__SETTEMP(comp_ctx, reg_target + 1);
+ duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, reg_target + 1); /* default instance */
+ DUK__SETTEMP(comp_ctx, reg_target + 2);
+
+ /* XXX: 'new obj.noSuch()' doesn't use GETPROPC now which
+ * makes the error message worse than for obj.noSuch().
+ */
if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
/* 'new' MemberExpression Arguments */
@@ -65767,17 +67286,14 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
nargs = 0;
}
- /* Opcode slot C is used in a non-standard way, so shuffling
- * is not allowed.
- */
duk__emit_a_bc(comp_ctx,
- DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A,
+ DUK_OP_CALL0 | DUK_BC_CALL_FLAG_CONSTRUCT,
nargs /*num_args*/,
reg_target /*target*/);
DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
- duk__ivalue_regconst(res, (duk_regconst_t) reg_target);
+ duk__ivalue_regconst(res, reg_target);
return;
}
@@ -65795,7 +67311,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
* duk__parse_func_like_fnum().
*/
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
duk_int_t fnum;
reg_temp = DUK__ALLOCTEMP(comp_ctx);
@@ -65806,10 +67322,10 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp /*a*/,
+ reg_temp /*a*/,
(duk_regconst_t) fnum /*bc*/);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
return;
}
@@ -65828,8 +67344,8 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
* resolving cases (the specification description is a bit confusing).
*/
- duk_reg_t reg_temp;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_temp;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
if (comp_ctx->curr_func.is_strict) {
@@ -65839,24 +67355,24 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
DUK__SETTEMP(comp_ctx, temp_at_entry);
reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
/* register bound variables are non-configurable -> always false */
duk__emit_bc(comp_ctx,
DUK_OP_LDFALSE,
- (duk_regconst_t) reg_temp);
+ reg_temp);
} else {
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
rc_varname = duk__getconst(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_DELVAR,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) rc_varname);
+ reg_temp,
+ rc_varname);
}
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
} else if (res->t == DUK_IVAL_PROP) {
- duk_reg_t reg_temp;
- duk_reg_t reg_obj;
+ duk_regconst_t reg_temp;
+ duk_regconst_t reg_obj;
duk_regconst_t rc_key;
DUK__SETTEMP(comp_ctx, temp_at_entry);
@@ -65865,21 +67381,21 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
DUK_OP_DELPROP | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_obj,
+ reg_temp,
+ reg_obj,
rc_key);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
} else {
/* non-Reference deletion is always 'true', even in strict mode */
- duk_push_true(ctx);
+ duk_push_true(thr);
goto plain_value;
}
return;
}
case DUK_TOK_VOID: {
duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
goto plain_value;
}
case DUK_TOK_TYPEOF: {
@@ -65891,11 +67407,11 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_VAR) {
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
"at compile time, need to use special run-time handling"));
@@ -65904,7 +67420,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
DUK_OP_TYPEOFID,
reg_temp,
rc_varname);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
return;
}
}
@@ -65924,7 +67440,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
/* unary plus */
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
- duk_is_number(ctx, res->x1.valstack_idx)) {
+ duk_is_number(thr, res->x1.valstack_idx)) {
/* unary plus of a number is identity */
return;
}
@@ -65935,14 +67451,14 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
/* unary minus */
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
- duk_is_number(ctx, res->x1.valstack_idx)) {
+ duk_is_number(thr, res->x1.valstack_idx)) {
/* this optimization is important to handle negative literals
* (which are not directly provided by the lexical grammar)
*/
duk_tval *tv_num;
duk_double_union du;
- tv_num = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
+ tv_num = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
DUK_ASSERT(tv_num != NULL);
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
du.d = DUK_TVAL_GET_NUMBER(tv_num);
@@ -65967,7 +67483,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
*/
duk_tval *tv_val;
- tv_val = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
+ tv_val = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
DUK_ASSERT(tv_val != NULL);
if (DUK_TVAL_IS_NUMBER(tv_val)) {
duk_double_t d;
@@ -65983,7 +67499,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
return;
}
} else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
- duk_small_int_t v;
+ duk_small_uint_t v;
v = DUK_TVAL_GET_BOOLEAN(tv_val);
DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
DUK_ASSERT(v == 0 || v == 1);
@@ -66007,10 +67523,10 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
* bits of the opcode.
*/
- duk_reg_t reg_src, reg_res;
+ duk_regconst_t reg_src, reg_res;
reg_src = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*flags*/);
- if (DUK__ISTEMP(comp_ctx, reg_src)) {
+ if (DUK__ISREG_TEMP(comp_ctx, reg_src)) {
reg_res = reg_src;
} else {
reg_res = DUK__ALLOCTEMP(comp_ctx);
@@ -66018,15 +67534,15 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk__emit_a_bc(comp_ctx,
args,
reg_res,
- (duk_regconst_t) reg_src);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_res);
+ reg_src);
+ duk__ivalue_regconst(res, reg_res);
return;
}
preincdec:
{
/* preincrement and predecrement */
- duk_reg_t reg_res;
+ duk_regconst_t reg_res;
duk_small_uint_t args_op1 = args & 0xff; /* DUK_OP_PREINCR/DUK_OP_PREDECR */
duk_small_uint_t args_op2 = args >> 8; /* DUK_OP_PREINCP_RR/DUK_OP_PREDECP_RR */
@@ -66039,39 +67555,39 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
if (res->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- h_varname = duk_known_hstring(ctx, res->x1.valstack_idx);
+ h_varname = duk_known_hstring(thr, res->x1.valstack_idx);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
goto syntax_error;
}
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
duk__emit_a_bc(comp_ctx,
args_op1, /* e.g. DUK_OP_PREINCR */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind);
+ reg_res,
+ reg_varbind);
} else {
duk__emit_a_bc(comp_ctx,
args_op1 + 4, /* e.g. DUK_OP_PREINCV */
- (duk_regconst_t) reg_res,
+ reg_res,
rc_varname);
}
DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
(duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
} else if (res->t == DUK_IVAL_PROP) {
- duk_reg_t reg_obj; /* allocate to reg only (not const) */
+ duk_regconst_t reg_obj; /* allocate to reg only (not const) */
duk_regconst_t rc_key;
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_PREINCP */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_obj,
+ reg_res,
+ reg_obj,
rc_key);
} else {
/* Technically return value is not needed because INVLHS will
@@ -66088,7 +67604,7 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
DUK_OP_INVLHS);
}
DUK__SETTEMP(comp_ctx, reg_res + 1);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_res);
+ duk__ivalue_regconst(res, reg_res);
return;
}
@@ -66099,6 +67615,11 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
return;
}
+#if defined(DUK_USE_ES6)
+ syntax_error_newtarget:
+ DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_NEWTARGET);
+#endif
+
syntax_error:
DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
}
@@ -66109,9 +67630,8 @@ DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
*/
DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_token *tk;
- duk_small_int_t tok;
+ duk_small_uint_t tok;
duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
/*
@@ -66161,8 +67681,8 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
res->t = DUK_IVAL_PROP;
duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- duk_replace(ctx, res->x2.valstack_idx);
+ duk_push_hstring(thr, comp_ctx->curr_token.str1);
+ duk_replace(thr, res->x2.valstack_idx);
res->x2.t = DUK_ISPEC_VALUE;
/* special RegExp literal handling after IdentifierName */
@@ -66204,9 +67724,9 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
case DUK_TOK_LPAREN: {
/* function call */
- duk_reg_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
+ duk_regconst_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
duk_int_t nargs;
- duk_small_uint_t call_op = DUK_OP_CALL;
+ duk_small_uint_t call_op = DUK_OP_CALL0;
/* XXX: attempt to get the call result to "next temp" whenever
* possible to avoid unnecessary register shuffles.
@@ -66222,12 +67742,12 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
if (left->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
- h_varname = duk_known_hstring(ctx, left->x1.valstack_idx);
+ h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
/* Potential direct eval call detected, flag the CALL
* so that a run-time "direct eval" check is made and
@@ -66237,16 +67757,16 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
"-> using EVALCALL, marking function "
"as may_direct_eval"));
- call_op = DUK_OP_EVALCALL;
+ call_op |= DUK_BC_CALL_FLAG_CALLED_AS_EVAL;
comp_ctx->curr_func.may_direct_eval = 1;
}
- duk_dup(ctx, left->x1.valstack_idx);
+ duk_dup(thr, left->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
duk__emit_a_bc(comp_ctx,
DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_varbind,
- (duk_regconst_t) (reg_cs + 0));
+ reg_varbind,
+ reg_cs + 0);
} else {
/* XXX: expand target register or constant field to
* reduce shuffling.
@@ -66254,7 +67774,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
DUK_ASSERT(DUK__ISCONST(rc_varname));
duk__emit_a_b(comp_ctx,
DUK_OP_CSVAR | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) (reg_cs + 0),
+ reg_cs + 0,
rc_varname);
}
} else if (left->t == DUK_IVAL_PROP) {
@@ -66263,34 +67783,61 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* but a typical call setup took 3 opcodes (e.g. LDREG, LDCONST,
* CSPROP) and the same can be achieved with ordinary loads.
*/
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ duk_regconst_t reg_key;
+#endif
+
DUK_DDD(DUK_DDDPRINT("function call with property base"));
+ /* XXX: For Math.sin() this generates: LDCONST + LDREG +
+ * GETPROPC + call. The LDREG is unnecessary because LDCONST
+ * could be loaded directly into reg_cs + 1. This doesn't
+ * happen now because a variable cannot be in left->x1 of a
+ * DUK_IVAL_PROP. We could notice that left->x1 is a temp
+ * and reuse, but it would still be in the wrong position
+ * (reg_cs + 0 rather than reg_cs + 1).
+ */
duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 1); /* base */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
+ duk__emit_a_b_c(comp_ctx,
+ DUK_OP_GETPROPC | DUK__EMIT_FLAG_BC_REGCONST,
+ reg_cs + 0,
+ reg_cs + 1,
+ reg_key);
+#else
duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); /* base[key] */
+#endif
} else {
DUK_DDD(DUK_DDDPRINT("function call with register base"));
duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
+#if 0
duk__emit_a_bc(comp_ctx,
DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) (reg_cs + 0)); /* in-place setup */
+ reg_cs + 0,
+ reg_cs + 0); /* in-place setup */
+#endif
+ /* Because of in-place setup, REGCS is equivalent to
+ * just this LDUNDEF.
+ */
+ duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, reg_cs + 1);
}
DUK__SETTEMP(comp_ctx, reg_cs + 2);
nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
- /* Tailcalls are handled by back-patching the opcode to TAILCALL to the
- * already emitted instruction later (in return statement parser).
+ /* Tailcalls are handled by back-patching the already emitted opcode
+ * later in return statement parser.
*/
duk__emit_a_bc(comp_ctx,
- call_op | DUK__EMIT_FLAG_NO_SHUFFLE_A,
+ call_op,
(duk_regconst_t) nargs /*numargs*/,
- (duk_regconst_t) reg_cs /*basereg*/);
+ reg_cs /*basereg*/);
DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */
- duk__ivalue_regconst(res, (duk_regconst_t) reg_cs);
+ duk__ivalue_regconst(res, reg_cs);
return;
}
@@ -66439,7 +67986,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
* but only if it really is a temp. Nothing fancy here now.
*/
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
duk_int_t pc_jump1;
duk_int_t pc_jump2;
@@ -66455,7 +68002,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__patch_jump_here(comp_ctx, pc_jump2);
DUK__SETTEMP(comp_ctx, reg_temp + 1);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
return;
}
@@ -66586,11 +68133,11 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
res->x2.t = res->x1.t;
res->x2.regconst = res->x1.regconst;
- duk_copy(ctx, res->x1.valstack_idx, res->x2.valstack_idx);
+ duk_copy(thr, res->x1.valstack_idx, res->x2.valstack_idx);
res->x1.t = left->x1.t;
res->x1.regconst = left->x1.regconst;
- duk_copy(ctx, left->x1.valstack_idx, res->x1.valstack_idx);
+ duk_copy(thr, left->x1.valstack_idx, res->x1.valstack_idx);
DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
(long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
@@ -66618,7 +68165,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
*/
{
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
duk_int_t pc_jump;
duk_small_uint_t args_truthval = args >> 8;
duk_small_uint_t args_rbp = args & 0xff;
@@ -66631,12 +68178,12 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
DUK_ASSERT(DUK__ISREG(reg_temp));
duk__emit_bc(comp_ctx,
(args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R),
- (duk_regconst_t) reg_temp); /* skip jump conditionally */
+ reg_temp); /* skip jump conditionally */
pc_jump = duk__emit_jump_empty(comp_ctx);
duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
duk__patch_jump_here(comp_ctx, pc_jump);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
+ duk__ivalue_regconst(res, reg_temp);
return;
}
@@ -66701,17 +68248,17 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
if (left->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
- h_varname = duk_known_hstring(ctx, left->x1.valstack_idx);
+ h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
/* E5 Section 11.13.1 (and others for other assignments), step 4. */
goto syntax_error_lvalue;
}
- duk_dup(ctx, left->x1.valstack_idx);
+ duk_dup(thr, left->x1.valstack_idx);
(void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
if (args_op == DUK_OP_NONE) {
@@ -66723,8 +68270,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/* 'res' must be a plain ivalue, and not register-bound variable. */
DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
- (res->x1.regconst & DUK__CONST_MARKER) == 0 &&
- !DUK__ISTEMP(comp_ctx, res->x1.regconst))) {
+ DUK__ISREG_NOTTEMP(comp_ctx, res->x1.regconst))) {
duk__ivalue_totempconst(comp_ctx, res);
}
}
@@ -66734,13 +68280,13 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* can change X, but when we do <op> we must use
* the pre-op value.
*/
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
reg_temp = DUK__ALLOCTEMP(comp_ctx);
if (reg_varbind >= 0) {
- duk_reg_t reg_res;
- duk_reg_t reg_src;
+ duk_regconst_t reg_res;
+ duk_regconst_t reg_src;
duk_int_t pc_temp_load;
duk_int_t pc_before_rhs;
duk_int_t pc_after_rhs;
@@ -66771,7 +68317,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
pc_temp_load = duk__get_current_pc(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_LDREG,
- (duk_regconst_t) reg_temp,
+ reg_temp,
reg_varbind);
pc_before_rhs = duk__get_current_pc(comp_ctx);
@@ -66789,7 +68335,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* one instruction, so use explicit PC computation.
*/
DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
- DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
+ DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (duk_size_t) (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
reg_src = reg_varbind;
} else {
DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
@@ -66798,14 +68344,14 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__emit_a_b_c(comp_ctx,
args_op | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_src,
+ reg_res,
+ reg_src,
res->x1.regconst);
- res->x1.regconst = (duk_regconst_t) reg_res;
+ res->x1.regconst = reg_res;
/* Ensure compact use of temps. */
- if (DUK__ISTEMP(comp_ctx, reg_res)) {
+ if (DUK__ISREG_TEMP(comp_ctx, reg_res)) {
DUK__SETTEMP(comp_ctx, reg_res + 1);
}
} else {
@@ -66815,7 +68361,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__emit_a_bc(comp_ctx,
DUK_OP_GETVAR,
- (duk_regconst_t) reg_temp,
+ reg_temp,
rc_varname);
duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
@@ -66823,10 +68369,10 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__emit_a_b_c(comp_ctx,
args_op | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_temp,
+ reg_temp,
+ reg_temp,
res->x1.regconst);
- res->x1.regconst = (duk_regconst_t) reg_temp;
+ res->x1.regconst = reg_temp;
}
DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
@@ -66879,10 +68425,10 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
/* 'res' contains expression value */
} else if (left->t == DUK_IVAL_PROP) {
/* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
- duk_reg_t reg_obj;
+ duk_regconst_t reg_obj;
duk_regconst_t rc_key;
duk_regconst_t rc_res;
- duk_reg_t reg_temp;
+ duk_regconst_t reg_temp;
/* Property access expressions ('a[b]') are critical to correct
* LHS evaluation ordering, see test-dev-assign-eval-order*.js.
@@ -66915,8 +68461,8 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_b_c(comp_ctx,
DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_obj,
+ reg_temp,
+ reg_obj,
rc_key);
duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
@@ -66924,19 +68470,19 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__emit_a_b_c(comp_ctx,
args_op | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_temp,
+ reg_temp,
+ reg_temp,
res->x1.regconst);
- rc_res = (duk_regconst_t) reg_temp;
+ rc_res = reg_temp;
}
duk__emit_a_b_c(comp_ctx,
DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_obj,
+ reg_obj,
rc_key,
rc_res);
- duk__ivalue_regconst(res, (duk_regconst_t) rc_res);
+ duk__ivalue_regconst(res, rc_res);
} else {
/* No support for lvalues returned from new or function call expressions.
* However, these must NOT cause compile-time SyntaxErrors, but run-time
@@ -66962,7 +68508,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
duk__emit_op_only(comp_ctx, DUK_OP_INVLHS);
- duk__ivalue_regconst(res, (duk_regconst_t) rc_res);
+ duk__ivalue_regconst(res, rc_res);
}
return;
@@ -66981,7 +68527,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
* the previous expression if a LineTerminator occurs before '++'/'--'.
*/
- duk_reg_t reg_res;
+ duk_regconst_t reg_res;
duk_small_uint_t args_op1 = (args >> 8) & 0xff; /* DUK_OP_POSTINCR/DUK_OP_POSTDECR */
duk_small_uint_t args_op2 = args >> 16; /* DUK_OP_POSTINCP_RR/DUK_OP_POSTDECP_RR */
@@ -66993,40 +68539,40 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
if (left->t == DUK_IVAL_VAR) {
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- h_varname = duk_known_hstring(ctx, left->x1.valstack_idx);
+ h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
goto syntax_error;
}
- duk_dup(ctx, left->x1.valstack_idx);
+ duk_dup(thr, left->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
duk__emit_a_bc(comp_ctx,
args_op1, /* e.g. DUK_OP_POSTINCR */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind);
+ reg_res,
+ reg_varbind);
} else {
duk__emit_a_bc(comp_ctx,
args_op1 + 4, /* e.g. DUK_OP_POSTINCV */
- (duk_regconst_t) reg_res,
+ reg_res,
rc_varname);
}
DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
(duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
} else if (left->t == DUK_IVAL_PROP) {
- duk_reg_t reg_obj; /* allocate to reg only (not const) */
+ duk_regconst_t reg_obj; /* allocate to reg only (not const) */
duk_regconst_t rc_key;
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_POSTINCP */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_obj,
+ reg_res,
+ reg_obj,
rc_key);
} else {
/* Technically return value is not needed because INVLHS will
@@ -67043,7 +68589,7 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
DUK__SETTEMP(comp_ctx, reg_res + 1);
- duk__ivalue_regconst(res, (duk_regconst_t) reg_res);
+ duk__ivalue_regconst(res, reg_res);
return;
}
@@ -67057,9 +68603,10 @@ DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_i
}
DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
- duk_small_int_t tok = comp_ctx->curr_token.t;
+ duk_small_uint_t tok = comp_ctx->curr_token.t;
- DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
+ DUK_ASSERT_DISABLE(tok >= DUK_TOK_MINVAL); /* unsigned */
+ DUK_ASSERT(tok <= DUK_TOK_MAXVAL);
DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
/* XXX: integrate support for this into led() instead?
@@ -67102,14 +68649,13 @@ DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
/* main expression parser function */
DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */
duk_ivalue *tmp = &tmp_alloc;
duk_small_uint_t rbp;
DUK__RECURSION_INCREASE(comp_ctx, thr);
- duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
+ duk_require_stack(thr, DUK__PARSE_EXPR_SLOTS);
/* filter out flags from exprtop rbp_flags here to save space */
rbp = rbp_flags & DUK__EXPR_RBP_MASK;
@@ -67119,10 +68665,10 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_
(long) comp_ctx->curr_func.paren_level));
DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc));
- tmp->x1.valstack_idx = duk_get_top(ctx);
+ tmp->x1.valstack_idx = duk_get_top(thr);
tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
+ duk_push_undefined(thr);
/* XXX: where to release temp regs in intermediate expressions?
* e.g. 1+2+3 -> don't inflate temp register count when parsing this.
@@ -67139,7 +68685,7 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_
if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
}
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
duk__ivalue_plain_fromstack(comp_ctx, res);
goto cleanup;
}
@@ -67155,7 +68701,7 @@ DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_
cleanup:
/* final result is already in 'res' */
- duk_pop_2(ctx);
+ duk_pop_2(thr);
DUK__RECURSION_DECREASE(comp_ctx, thr);
}
@@ -67186,20 +68732,20 @@ DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_sma
*/
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__expr(comp_ctx, res, rbp_flags);
return duk__ivalue_toreg(comp_ctx, res);
}
#endif
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__expr(comp_ctx, res, rbp_flags);
return duk__ivalue_totemp(comp_ctx, res);
}
#endif
-DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
DUK_ASSERT(forced_reg >= 0);
duk__expr(comp_ctx, res, rbp_flags);
duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
@@ -67227,19 +68773,19 @@ DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *
duk__ivalue_toplain_ignore(comp_ctx, res);
}
-DUK_LOCAL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__exprtop(comp_ctx, res, rbp_flags);
return duk__ivalue_toreg(comp_ctx, res);
}
#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
+DUK_LOCAL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
duk__exprtop(comp_ctx, res, rbp_flags);
return duk__ivalue_totemp(comp_ctx, res);
}
#endif
-DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
+DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
DUK_ASSERT(forced_reg >= 0);
duk__exprtop(comp_ctx, res, rbp_flags);
duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
@@ -67293,11 +68839,10 @@ DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalu
* as is done in 'for-in' parsing.
*/
-DUK_LOCAL 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 void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h_varname;
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
/* assume 'var' has been eaten */
@@ -67320,17 +68865,17 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
duk_uarridx_t n;
DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
(duk_heaphdr *) h_varname));
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
- duk_push_hstring(ctx, h_varname);
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
- duk_push_int(ctx, DUK_DECL_TYPE_VAR + (0 << 8));
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
+ n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
+ duk_push_hstring(thr, h_varname);
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
+ duk_push_int(thr, DUK_DECL_TYPE_VAR + (0 << 8));
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
}
- duk_push_hstring(ctx, h_varname); /* push before advancing to keep reachable */
+ duk_push_hstring(thr, h_varname); /* push before advancing to keep reachable */
/* register binding lookup is based on varmap (even in first pass) */
- duk_dup_top(ctx);
+ duk_dup_top(thr);
(void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
duk__advance(comp_ctx); /* eat identifier */
@@ -67346,11 +68891,11 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
if (reg_varbind >= 0) {
duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
} else {
- duk_reg_t reg_val;
+ duk_regconst_t reg_val;
reg_val = duk__ivalue_toreg(comp_ctx, res);
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_val,
+ reg_val,
rc_varname);
}
} else {
@@ -67360,7 +68905,7 @@ DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
}
}
- duk_pop(ctx); /* pop varname */
+ duk_pop(thr); /* pop varname */
*out_rc_varname = rc_varname;
*out_reg_varbind = reg_varbind;
@@ -67372,7 +68917,7 @@ DUK_LOCAL void duk__parse_var_decl(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 reg_varbind;
duk_regconst_t rc_varname;
duk__advance(comp_ctx); /* eat 'var' */
@@ -67390,10 +68935,9 @@ DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
- duk_reg_t temp_reset; /* knock back "next temp" to this whenever possible */
- duk_reg_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
+ duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
+ duk_regconst_t temp_reset; /* knock back "next temp" to this whenever possible */
+ duk_regconst_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
@@ -67436,7 +68980,7 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
* Variant 2 or 4
*/
- duk_reg_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
+ duk_regconst_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */
duk__advance(comp_ctx); /* eat 'var' */
@@ -67453,12 +68997,12 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
if (reg_varbind >= 0) {
duk__emit_a_bc(comp_ctx,
DUK_OP_LDREG,
- (duk_regconst_t) reg_varbind,
- (duk_regconst_t) (reg_temps + 0));
+ reg_varbind,
+ reg_temps + 0);
} else {
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_temps + 0),
+ reg_temps + 0,
rc_varname);
}
goto parse_3_or_4;
@@ -67505,34 +69049,34 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
}
if (res->t == DUK_IVAL_VAR) {
- duk_reg_t reg_varbind;
+ duk_regconst_t reg_varbind;
duk_regconst_t rc_varname;
- duk_dup(ctx, res->x1.valstack_idx);
+ duk_dup(thr, res->x1.valstack_idx);
if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
duk__emit_a_bc(comp_ctx,
DUK_OP_LDREG,
- (duk_regconst_t) reg_varbind,
- (duk_regconst_t) (reg_temps + 0));
+ reg_varbind,
+ reg_temps + 0);
} else {
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_temps + 0),
+ reg_temps + 0,
rc_varname);
}
} else if (res->t == DUK_IVAL_PROP) {
/* Don't allow a constant for the object (even for a number etc), as
* it goes into the 'A' field of the opcode.
*/
- duk_reg_t reg_obj;
+ duk_regconst_t reg_obj;
duk_regconst_t rc_key;
reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
duk__emit_a_b_c(comp_ctx,
DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_obj,
+ reg_obj,
rc_key,
- (duk_regconst_t) (reg_temps + 0));
+ reg_temps + 0);
} else {
duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
duk__emit_op_only(comp_ctx,
@@ -67652,7 +69196,7 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
{
duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
- duk_reg_t reg_target;
+ duk_regconst_t reg_target;
DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
@@ -67687,8 +69231,8 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */
duk__emit_b_c(comp_ctx,
DUK_OP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
- (duk_regconst_t) (reg_temps + 1),
- (duk_regconst_t) reg_target);
+ reg_temps + 1,
+ reg_target);
pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
DUK__SETTEMP(comp_ctx, temp_reset);
@@ -67707,8 +69251,8 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
pc_l4 = duk__get_current_pc(comp_ctx);
duk__emit_b_c(comp_ctx,
DUK_OP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
- (duk_regconst_t) (reg_temps + 0),
- (duk_regconst_t) (reg_temps + 1));
+ reg_temps + 0,
+ reg_temps + 1);
pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */
duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */
@@ -67745,10 +69289,10 @@ DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res,
DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
duk_hthread *thr = comp_ctx->thr;
- duk_reg_t temp_at_loop;
+ duk_regconst_t temp_at_loop;
duk_regconst_t rc_switch; /* reg/const for switch value */
duk_regconst_t rc_case; /* reg/const for case value */
- duk_reg_t reg_temp; /* general temp register */
+ duk_regconst_t reg_temp; /* general temp register */
duk_int_t pc_prevcase = -1;
duk_int_t pc_prevstmt = -1;
duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */
@@ -67791,7 +69335,7 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
for (;;) {
duk_int_t num_stmts;
- duk_small_int_t tok;
+ duk_small_uint_t tok;
/* sufficient for keeping temp reg numbers in check */
DUK__SETTEMP(comp_ctx, temp_at_loop);
@@ -67823,10 +69367,10 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
reg_temp = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_b_c(comp_ctx,
DUK_OP_SEQ | DUK__EMIT_FLAG_BC_REGCONST,
- (duk_regconst_t) reg_temp,
+ reg_temp,
rc_switch,
rc_case);
- duk__emit_if_true_skip(comp_ctx, (duk_regconst_t) reg_temp);
+ duk__emit_if_true_skip(comp_ctx, reg_temp);
/* jump to next case clause */
pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
@@ -67943,7 +69487,7 @@ DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
}
DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_reg_t temp_reset;
+ duk_regconst_t temp_reset;
duk_regconst_t rc_cond;
duk_int_t pc_jump_false;
@@ -68017,7 +69561,7 @@ DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, d
}
DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
- duk_reg_t temp_reset;
+ duk_regconst_t temp_reset;
duk_regconst_t rc_cond;
duk_int_t pc_start;
duk_int_t pc_jump_false;
@@ -68136,7 +69680,7 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
pc_after_expr = duk__get_current_pc(comp_ctx);
/* Tail call check: if last opcode emitted was CALL, and
- * the context allows it, change the CALL to TAILCALL.
+ * the context allows it, add a tailcall flag to the CALL.
* This doesn't guarantee that a tail call will be allowed at
* runtime, so the RETURN must still be emitted. (Duktape
* 0.10.0 avoided this and simulated a RETURN if a tail call
@@ -68182,13 +69726,13 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
ins = instr->ins;
op = (duk_small_uint_t) DUK_DEC_OP(ins);
- if (op == DUK_OP_CALL &&
- DUK__ISTEMP(comp_ctx, rc_val) /* see above */) {
+ if ((op & ~0x0fU) == DUK_OP_CALL0 &&
+ DUK__ISREG_TEMP(comp_ctx, rc_val) /* see above */) {
DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
"catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
"and last instruction is a CALL "
"-> change to TAILCALL"));
- ins = (ins & ~DUK_BC_SHIFTED_MASK_OP) | (DUK_OP_TAILCALL << DUK_BC_SHIFT_OP);
+ ins |= DUK_ENC_OP(DUK_BC_CALL_FLAG_TAILCALL);
instr->ins = ins;
}
}
@@ -68208,7 +69752,7 @@ DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *re
}
DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_reg_t reg_val;
+ duk_regconst_t reg_val;
duk__advance(comp_ctx); /* eat 'throw' */
@@ -68221,13 +69765,12 @@ DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res
reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
duk__emit_bc(comp_ctx,
DUK_OP_THROW,
- (duk_regconst_t) reg_val);
+ reg_val);
}
DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
+ duk_regconst_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
duk_regconst_t rc_varname = 0;
duk_small_uint_t trycatch_flags = 0;
duk_int_t pc_ldconst = -1;
@@ -68301,7 +69844,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk_hstring *h_var;
duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
- DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx)));
+ DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(thr)));
trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
@@ -68317,7 +69860,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
h_var = comp_ctx->curr_token.str1;
DUK_ASSERT(h_var != NULL);
- duk_push_hstring(ctx, h_var); /* keep in on valstack, use borrowed ref below */
+ duk_push_hstring(thr, h_var); /* keep in on valstack, use borrowed ref below */
if (comp_ctx->curr_func.is_strict &&
((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
@@ -68326,7 +69869,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
goto syntax_error;
}
- duk_dup_top(ctx);
+ duk_dup_top(thr);
rc_varname = duk__getconst(comp_ctx);
DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
(unsigned long) rc_varname, (long) rc_varname));
@@ -68337,60 +69880,60 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
- duk_dup_top(ctx);
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- if (duk_is_undefined(ctx, -1)) {
+ duk_dup_top(thr);
+ duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
+ if (duk_is_undefined(thr, -1)) {
varmap_value = -2;
- } else if (duk_is_null(ctx, -1)) {
+ } else if (duk_is_null(thr, -1)) {
varmap_value = -1;
} else {
- DUK_ASSERT(duk_is_number(ctx, -1));
- varmap_value = duk_get_int(ctx, -1);
+ DUK_ASSERT(duk_is_number(thr, -1));
+ varmap_value = duk_get_int(thr, -1);
DUK_ASSERT(varmap_value >= 0);
}
- duk_pop(ctx);
+ duk_pop(thr);
#if 0
/* It'd be nice to do something like this - but it doesn't
* work for closures created inside the catch clause.
*/
- duk_dup_top(ctx);
- duk_push_int(ctx, (duk_int_t) (reg_catch + 0));
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_dup_top(thr);
+ duk_push_int(thr, (duk_int_t) (reg_catch + 0));
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
#endif
- duk_dup_top(ctx);
- duk_push_null(ctx);
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_dup_top(thr);
+ duk_push_null(thr);
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
duk__emit_a_bc(comp_ctx,
DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_catch + 0) /*value*/,
+ reg_catch + 0 /*value*/,
rc_varname /*varname*/);
DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
/* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
if (varmap_value == -2) {
/* not present */
- duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_del_prop(thr, comp_ctx->curr_func.varmap_idx);
} else {
if (varmap_value == -1) {
- duk_push_null(ctx);
+ duk_push_null(thr);
} else {
DUK_ASSERT(varmap_value >= 0);
- duk_push_int(ctx, varmap_value);
+ duk_push_int(thr, varmap_value);
}
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
}
/* varname is popped by above code */
DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
duk__emit_op_only(comp_ctx,
DUK_OP_ENDCATCH);
@@ -68403,7 +69946,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
- DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx)));
+ DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(thr)));
}
if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
@@ -68416,9 +69959,9 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
/* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
- duk__emit_b(comp_ctx,
- DUK_OP_ENDFIN,
- reg_catch); /* rethrow */
+ duk__emit_abc(comp_ctx,
+ DUK_OP_ENDFIN,
+ reg_catch); /* rethrow */
}
if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
@@ -68462,7 +70005,7 @@ DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
duk_int_t pc_trycatch;
duk_int_t pc_finished;
- duk_reg_t reg_catch;
+ duk_regconst_t reg_catch;
duk_small_uint_t trycatch_flags;
if (comp_ctx->curr_func.is_strict) {
@@ -68484,7 +70027,7 @@ DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res)
duk__emit_a_bc(comp_ctx,
DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
(duk_regconst_t) trycatch_flags /*a*/,
- (duk_regconst_t) reg_catch /*bc*/);
+ reg_catch /*bc*/);
duk__emit_invalid(comp_ctx); /* catch jump */
duk__emit_invalid(comp_ctx); /* finished jump */
@@ -68524,10 +70067,9 @@ DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t l
*/
DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */
- duk_reg_t temp_at_entry;
- duk_uarridx_t labels_len_at_entry;
+ duk_regconst_t temp_at_entry;
+ duk_size_t labels_len_at_entry;
duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */
duk_int_t stmt_id;
duk_small_uint_t stmt_flags = 0;
@@ -68539,7 +70081,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
temp_at_entry = DUK__GETTEMP(comp_ctx);
pc_at_entry = duk__get_current_pc(comp_ctx);
- labels_len_at_entry = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.labelnames_idx);
+ labels_len_at_entry = duk_get_length(thr, comp_ctx->curr_func.labelnames_idx);
stmt_id = comp_ctx->curr_func.stmt_next++;
dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
@@ -68624,7 +70166,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
DUK_DDD(DUK_DDDPRINT("function declaration statement"));
#if defined(DUK_USE_ASSERTIONS)
- top_before = duk_get_top(ctx);
+ top_before = duk_get_top(thr);
#endif
duk__advance(comp_ctx); /* eat 'function' */
@@ -68638,18 +70180,18 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
duk_uarridx_t n;
#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == top_before + 1);
+ DUK_ASSERT(duk_get_top(thr) == top_before + 1);
#endif
DUK_DDD(DUK_DDDPRINT("register function declaration %!T in pass 1, fnum %ld",
- duk_get_tval(ctx, -1), (long) fnum));
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
+ duk_get_tval(thr, -1), (long) fnum));
+ n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
/* funcname is at index -1 */
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
- duk_push_int(ctx, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
+ duk_push_int(thr, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
+ duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
} else {
#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == top_before);
+ DUK_ASSERT(duk_get_top(thr) == top_before);
#endif
}
@@ -68860,7 +70402,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
/* expected ival */
DUK_ASSERT(res->t == DUK_IVAL_VAR);
DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
- DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
+ DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
h_lab = comp_ctx->prev_token.str1;
DUK_ASSERT(h_lab != NULL);
@@ -68898,7 +70440,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
/* expected ival */
DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
- DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
+ DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
h_dir = comp_ctx->prev_token.str1;
DUK_ASSERT(h_dir != NULL);
@@ -68966,7 +70508,7 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
*/
if (stmt_flags & DUK__HAS_VAL) {
- duk_reg_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
+ duk_regconst_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
if (reg_stmt_value >= 0) {
duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
} else {
@@ -69045,13 +70587,12 @@ DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_
DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_ivalue res_alloc;
duk_ivalue *res = &res_alloc;
/* Setup state. Initial ivalue is 'undefined'. */
- duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
+ duk_require_stack(thr, DUK__PARSE_STATEMENTS_SLOTS);
/* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
* intermediate values suffice for parsing of each function. Nesting is needed
@@ -69061,10 +70602,10 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou
DUK_MEMZERO(&res_alloc, sizeof(res_alloc));
res->t = DUK_IVAL_PLAIN;
res->x1.t = DUK_ISPEC_VALUE;
- res->x1.valstack_idx = duk_get_top(ctx);
+ res->x1.valstack_idx = duk_get_top(thr);
res->x2.valstack_idx = res->x1.valstack_idx + 1;
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
+ duk_push_undefined(thr);
/* Parse statements until a closing token (EOF or '}') is found. */
@@ -69096,7 +70637,7 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou
/* Tear down state. */
- duk_pop_2(ctx);
+ duk_pop_2(thr);
}
/*
@@ -69131,9 +70672,8 @@ DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_sou
* handle cases with a very large number of variables?
*/
-DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg) {
+DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h_name;
duk_bool_t configurable_bindings;
duk_uarridx_t num_args;
@@ -69146,7 +70686,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
#endif
#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
#endif
/*
@@ -69163,21 +70703,21 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* (there's no support for shuffling them now).
*/
- num_args = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
+ num_args = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
/* XXX: check num_args */
for (i = 0; i < num_args; i++) {
- duk_get_prop_index(ctx, comp_ctx->curr_func.argnames_idx, i);
- h_name = duk_known_hstring(ctx, -1);
+ duk_get_prop_index(thr, comp_ctx->curr_func.argnames_idx, i);
+ h_name = duk_known_hstring(thr, -1);
if (comp_ctx->curr_func.is_strict) {
if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
goto error_argname;
}
- duk_dup_top(ctx);
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
+ duk_dup_top(thr);
+ if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
goto error_argname;
}
@@ -69202,14 +70742,14 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
/* only functions can have arguments */
DUK_ASSERT(comp_ctx->curr_func.is_function);
- duk_push_uarridx(ctx, i); /* -> [ ... name index ] */
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
+ duk_push_uarridx(thr, i); /* -> [ ... name index ] */
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
/* no code needs to be emitted, the regs already have values */
}
/* use temp_next for tracking register allocations */
- DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_reg_t) num_args);
+ DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_regconst_t) num_args);
/*
* After arguments, allocate special registers (like shuffling temps)
@@ -69219,7 +70759,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
*out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
}
if (comp_ctx->curr_func.needs_shuffle) {
- duk_reg_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
+ duk_regconst_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
comp_ctx->curr_func.shuffle1 = shuffle_base;
comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
@@ -69237,47 +70777,47 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* Function declarations
*/
- num_decls = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
+ num_decls = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
(long) num_decls,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.decls_idx)));
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.decls_idx)));
for (i = 0; i < num_decls; i += 2) {
duk_int_t decl_type;
duk_int_t fnum;
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
- decl_type = duk_to_int(ctx, -1);
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
+ decl_type = duk_to_int(thr, -1);
fnum = decl_type >> 8; /* XXX: macros */
decl_type = decl_type & 0xff;
- duk_pop(ctx);
+ duk_pop(thr);
if (decl_type != DUK_DECL_TYPE_FUNC) {
continue;
}
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
/* XXX: spilling */
if (comp_ctx->curr_func.is_function) {
- duk_reg_t reg_bind;
- duk_dup_top(ctx);
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
+ duk_regconst_t reg_bind;
+ duk_dup_top(thr);
+ if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
/* shadowed; update value */
- duk_dup_top(ctx);
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- reg_bind = duk_to_int(ctx, -1); /* [ ... name reg_bind ] */
+ duk_dup_top(thr);
+ duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
+ reg_bind = duk_to_int(thr, -1); /* [ ... name reg_bind ] */
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_bind,
+ reg_bind,
(duk_regconst_t) fnum);
} else {
/* function: always register bound */
reg_bind = DUK__ALLOCTEMP(comp_ctx);
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_bind,
+ reg_bind,
(duk_regconst_t) fnum);
- duk_push_int(ctx, (duk_int_t) reg_bind);
+ duk_push_int(thr, (duk_int_t) reg_bind);
}
} else {
/* Function declaration for global/eval code is emitted even
@@ -69288,14 +70828,14 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* update the binding value.
*/
- duk_reg_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_dup_top(ctx);
+ duk_regconst_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
+ duk_dup_top(thr);
rc_name = duk__getconst(comp_ctx);
- duk_push_null(ctx);
+ duk_push_null(thr);
duk__emit_a_bc(comp_ctx,
DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp,
+ reg_temp,
(duk_regconst_t) fnum);
declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
@@ -69310,19 +70850,19 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
(duk_regconst_t) declvar_flags /*flags*/,
rc_name /*name*/,
- (duk_regconst_t) reg_temp /*value*/);
+ reg_temp /*value*/);
DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
}
DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(ctx, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(ctx, -1)));
+ DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(thr, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(thr, -1)));
#endif
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
}
/*
@@ -69332,7 +70872,7 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
* 'arguments' is referenced inside the function body.
*/
- if (duk_has_prop_stridx(ctx, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
+ if (duk_has_prop_stridx(thr, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
"-> arguments object creation can be skipped"));
comp_ctx->curr_func.is_arguments_shadowed = 1;
@@ -69349,22 +70889,22 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
for (i = 0; i < num_decls; i += 2) {
duk_int_t decl_type;
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
- decl_type = duk_to_int(ctx, -1);
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
+ decl_type = duk_to_int(thr, -1);
decl_type = decl_type & 0xff;
- duk_pop(ctx);
+ duk_pop(thr);
if (decl_type != DUK_DECL_TYPE_VAR) {
continue;
}
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
+ if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
/* shadowed, ignore */
} else {
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
- h_name = duk_known_hstring(ctx, -1);
+ duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
+ h_name = duk_known_hstring(thr, -1);
if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
!comp_ctx->curr_func.is_arguments_shadowed) {
@@ -69372,19 +70912,19 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
"but appears as a variable declaration -> treat as "
"a no-op for variable declaration purposes"));
- duk_pop(ctx);
+ duk_pop(thr);
continue;
}
/* XXX: spilling */
if (comp_ctx->curr_func.is_function) {
- duk_reg_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
+ duk_regconst_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
/* no need to init reg, it will be undefined on entry */
- duk_push_int(ctx, (duk_int_t) reg_bind);
+ duk_push_int(thr, (duk_int_t) reg_bind);
} else {
- duk_dup_top(ctx);
+ duk_dup_top(thr);
rc_name = duk__getconst(comp_ctx);
- duk_push_null(ctx);
+ duk_push_null(thr);
declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
DUK_PROPDESC_FLAG_ENUMERABLE;
@@ -69396,10 +70936,10 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
(duk_regconst_t) declvar_flags /*flags*/,
rc_name /*name*/,
- (duk_regconst_t) 0 /*value*/);
+ 0 /*value*/);
}
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
+ duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
}
}
@@ -69408,10 +70948,10 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
*/
DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx),
+ (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx),
(long) comp_ctx->curr_func.is_arguments_shadowed));
- DUK_ASSERT_TOP(ctx, entry_top);
+ DUK_ASSERT_TOP(thr, entry_top);
return;
error_outofregs:
@@ -69462,16 +71002,14 @@ DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ct
DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token) {
duk_compiler_func *func;
duk_hthread *thr;
- duk_context *ctx;
- duk_reg_t reg_stmt_value = -1;
+ duk_regconst_t reg_stmt_value = -1;
duk_lexer_point lex_pt;
- duk_reg_t temp_first;
+ duk_regconst_t temp_first;
duk_small_int_t compile_round = 1;
DUK_ASSERT(comp_ctx != NULL);
thr = comp_ctx->thr;
- ctx = (duk_context *) thr;
DUK_ASSERT(thr != NULL);
func = &comp_ctx->curr_func;
@@ -69479,7 +71017,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
DUK__RECURSION_INCREASE(comp_ctx, thr);
- duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
+ duk_require_stack(thr, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
/*
* Store lexer position for a later rewind
@@ -69694,7 +71232,7 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
if (reg_stmt_value >= 0) {
DUK_ASSERT(DUK__ISREG(reg_stmt_value));
- duk__emit_bc(comp_ctx, DUK_OP_RETREG, (duk_regconst_t) reg_stmt_value /*reg*/);
+ duk__emit_bc(comp_ctx, DUK_OP_RETREG, reg_stmt_value /*reg*/);
} else {
duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
}
@@ -69737,7 +71275,6 @@ DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expec
/* Parse formals. */
DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_bool_t first = 1;
duk_uarridx_t n;
@@ -69763,7 +71300,7 @@ DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
*/
if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
- DUK_ERROR_SYNTAX(thr, "expected identifier");
+ DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
}
DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
@@ -69771,9 +71308,9 @@ DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
(duk_heaphdr *) comp_ctx->curr_token.str1));
/* XXX: append primitive */
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
- duk_put_prop_index(ctx, comp_ctx->curr_func.argnames_idx, n);
+ duk_push_hstring(thr, comp_ctx->curr_token.str1);
+ n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
+ duk_put_prop_index(thr, comp_ctx->curr_func.argnames_idx, n);
duk__advance(comp_ctx); /* eat identifier */
}
@@ -69785,7 +71322,6 @@ DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
*/
DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_token *tok;
duk_bool_t no_advance;
@@ -69824,22 +71360,22 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_ui
if (flags & DUK__FUNC_FLAG_GETSET) {
/* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t == DUK_TOK_STRING) {
- duk_push_hstring(ctx, tok->str1); /* keep in valstack */
+ duk_push_hstring(thr, tok->str1); /* keep in valstack */
} else if (tok->t == DUK_TOK_NUMBER) {
- duk_push_number(ctx, tok->num);
- duk_to_string(ctx, -1);
+ duk_push_number(thr, tok->num);
+ duk_to_string(thr, -1);
} else {
DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
}
- comp_ctx->curr_func.h_name = duk_known_hstring(ctx, -1); /* borrowed reference */
+ comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */
} else {
/* Function name is an Identifier (not IdentifierName), but we get
* the raw name (not recognizing keywords) here and perform the name
* checks only after pass 1.
*/
if (tok->t_nores == DUK_TOK_IDENTIFIER) {
- duk_push_hstring(ctx, tok->str1); /* keep in valstack */
- comp_ctx->curr_func.h_name = duk_known_hstring(ctx, -1); /* borrowed reference */
+ duk_push_hstring(thr, tok->str1); /* keep in valstack */
+ comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */
} else {
/* valstack will be unbalanced, which is OK */
DUK_ASSERT((flags & DUK__FUNC_FLAG_GETSET) == 0);
@@ -69906,7 +71442,6 @@ DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_ui
*/
DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
duk_compiler_func old_func;
duk_idx_t entry_top;
duk_int_t fnum;
@@ -69919,12 +71454,12 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm
duk_lexer_point lex_pt;
fnum = comp_ctx->curr_func.fnum_next++;
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
- lex_pt.offset = duk_to_int(ctx, -1);
- duk_pop(ctx);
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
- lex_pt.line = duk_to_int(ctx, -1);
- duk_pop(ctx);
+ duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
+ lex_pt.offset = (duk_size_t) duk_to_uint(thr, -1);
+ duk_pop(thr);
+ duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
+ lex_pt.line = duk_to_int(thr, -1);
+ duk_pop(thr);
DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
(long) lex_pt.offset, (long) lex_pt.line));
@@ -69943,7 +71478,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm
* to restore it later, and switch to using a new function in comp_ctx.
*/
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
(long) entry_top, (long) comp_ctx->curr_token.start_offset));
@@ -69986,7 +71521,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm
DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
/* XXX: append primitive */
- DUK_ASSERT(duk_get_length(ctx, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
+ DUK_ASSERT(duk_get_length(thr, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
fnum = old_func.fnum_next++;
if (fnum > DUK__MAX_FUNCS) {
@@ -69994,11 +71529,11 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm
}
/* array writes autoincrement length */
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
- duk_push_size_t(ctx, comp_ctx->prev_token.start_offset);
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
- duk_push_int(ctx, comp_ctx->prev_token.start_line);
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
+ (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
+ duk_push_size_t(thr, comp_ctx->prev_token.start_offset);
+ (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
+ duk_push_int(thr, comp_ctx->prev_token.start_line);
+ (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
/*
* Cleanup: restore original function, restore valstack state.
@@ -70009,11 +71544,11 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm
if (flags & DUK__FUNC_FLAG_PUSHNAME_PASS1) {
DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
- duk_push_hstring(ctx, comp_ctx->curr_func.h_name);
- duk_replace(ctx, entry_top);
- duk_set_top(ctx, entry_top + 1);
+ duk_push_hstring(thr, comp_ctx->curr_func.h_name);
+ duk_replace(thr, entry_top);
+ duk_set_top(thr, entry_top + 1);
} else {
- duk_set_top(ctx, entry_top);
+ duk_set_top(thr, entry_top);
}
DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
@@ -70034,8 +71569,7 @@ DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_sm
/* XXX: source code property */
-DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_hthread *thr, void *udata) {
duk_hstring *h_filename;
duk__compiler_stkstate *comp_stk;
duk_compiler_ctx *comp_ctx;
@@ -70054,7 +71588,7 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
* Arguments check
*/
- entry_top = duk_get_top(ctx);
+ entry_top = duk_get_top(thr);
DUK_ASSERT(entry_top >= 1);
comp_stk = (duk__compiler_stkstate *) udata;
@@ -70068,7 +71602,7 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0);
is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0);
- h_filename = duk_get_hstring(ctx, -1); /* may be undefined */
+ h_filename = duk_get_hstring(thr, -1); /* may be undefined */
/*
* Init compiler and lexer contexts
@@ -70084,13 +71618,13 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
comp_ctx->curr_token.str2 = NULL;
#endif
- duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
+ duk_require_stack(thr, DUK__COMPILE_ENTRY_SLOTS);
- duk_push_dynamic_buffer(ctx, 0); /* entry_top + 0 */
- duk_push_undefined(ctx); /* entry_top + 1 */
- duk_push_undefined(ctx); /* entry_top + 2 */
- duk_push_undefined(ctx); /* entry_top + 3 */
- duk_push_undefined(ctx); /* entry_top + 4 */
+ duk_push_dynamic_buffer(thr, 0); /* entry_top + 0 */
+ duk_push_undefined(thr); /* entry_top + 1 */
+ duk_push_undefined(thr); /* entry_top + 2 */
+ duk_push_undefined(thr); /* entry_top + 3 */
+ duk_push_undefined(thr); /* entry_top + 4 */
comp_ctx->thr = thr;
comp_ctx->h_filename = h_filename;
@@ -70108,7 +71642,7 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
comp_ctx->lex.buf_idx = entry_top + 0;
- comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, entry_top + 0);
+ comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 0);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
@@ -70131,9 +71665,9 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
*/
DUK_ASSERT(func->h_name == NULL);
} else {
- duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
+ duk_push_hstring_stridx(thr, (is_eval ? DUK_STRIDX_EVAL :
DUK_STRIDX_GLOBAL));
- func->h_name = duk_get_hstring(ctx, -1);
+ func->h_name = duk_get_hstring(thr, -1);
}
/*
@@ -70185,7 +71719,6 @@ DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
}
DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
duk__compiler_stkstate comp_stk;
duk_compiler_ctx *prev_ctx;
duk_ret_t safe_rc;
@@ -70205,12 +71738,12 @@ 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, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nret*/);
+ safe_rc = duk_safe_call(thr, duk__js_compile_raw, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
if (safe_rc != DUK_EXEC_SUCCESS) {
- DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(ctx, -1)));
- (void) duk_throw(ctx);
+ DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(thr, -1)));
+ (void) duk_throw(thr);
}
/* [ ... template ] */
@@ -70271,7 +71804,8 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer
#undef DUK__HAS_VAL
#undef DUK__ISCONST
#undef DUK__ISREG
-#undef DUK__ISTEMP
+#undef DUK__ISREG_NOTTEMP
+#undef DUK__ISREG_TEMP
#undef DUK__IS_TERMINAL
#undef DUK__IVAL_FLAG_ALLOW_CONST
#undef DUK__IVAL_FLAG_REQUIRE_SHORT
@@ -70309,7 +71843,7 @@ DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer
* Local declarations.
*/
-DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top);
+DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act);
/*
* Misc helpers.
@@ -70318,8 +71852,10 @@ DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, du
/* Forced inline declaration, only applied for performance oriented build. */
#if defined(DUK_USE_EXEC_PREFER_SIZE)
#define DUK__INLINE_PERF
+#define DUK__NOINLINE_PERF
#else
#define DUK__INLINE_PERF DUK_ALWAYS_INLINE
+#define DUK__NOINLINE_PERF DUK_NOINLINE
#endif
/* Replace value stack top to value at 'tv_ptr'. Optimize for
@@ -70331,7 +71867,7 @@ DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, du
duk_tval *duk__tvdst; \
duk_tval duk__tvtmp; \
duk__thr = (thr); \
- duk__tvsrc = DUK_GET_TVAL_NEGIDX((duk_context *) duk__thr, -1); \
+ duk__tvsrc = DUK_GET_TVAL_NEGIDX(duk__thr, -1); \
duk__tvdst = (tv_ptr); \
DUK_TVAL_SET_TVAL(&duk__tvtmp, duk__tvdst); \
DUK_TVAL_SET_TVAL(duk__tvdst, duk__tvsrc); \
@@ -70341,7 +71877,7 @@ DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, du
} while (0)
/* XXX: candidate of being an internal shared API call */
-#if !defined(DUK_USE_EXEC_PREFER_SIZE)
+#if 0 /* unused */
DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, duk_small_uint_fast_t count) {
duk_tval *tv_dst;
duk_size_t copy_size;
@@ -70400,15 +71936,13 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv
* Custom types also have special behavior implemented here.
*/
- duk_context *ctx = (duk_context *) thr;
duk_double_union du;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_x != NULL); /* may be reg or const */
DUK_ASSERT(tv_y != NULL); /* may be reg or const */
DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
+ DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
/*
* Fast paths
@@ -70428,7 +71962,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv
v2 = DUK_TVAL_GET_FASTINT(tv_y);
v3 = v1 + v2;
v3_hi = (duk_int32_t) (v3 >> 32);
- if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
+ if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
return;
@@ -70446,8 +71980,8 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv
du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
#if defined(DUK_USE_EXEC_PREFER_SIZE)
- duk_push_number(ctx, du.d); /* will NaN normalize result */
- duk_replace(ctx, idx_z);
+ duk_push_number(thr, du.d); /* will NaN normalize result */
+ duk_replace(thr, (duk_idx_t) idx_z);
#else /* DUK_USE_EXEC_PREFER_SIZE */
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
@@ -70461,40 +71995,38 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv
* Slow path: potentially requires function calls for coercion
*/
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
- duk_to_primitive(ctx, -1, DUK_HINT_NONE);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_to_primitive(thr, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
+ duk_to_primitive(thr, -1, DUK_HINT_NONE);
/* Since Duktape 2.x plain buffers are treated like ArrayBuffer. */
- if (duk_is_string(ctx, -2) || duk_is_string(ctx, -1)) {
+ if (duk_is_string(thr, -2) || duk_is_string(thr, -1)) {
/* Symbols shouldn't technically be handled here, but should
* go into the default ToNumber() coercion path instead and
* fail there with a TypeError. However, there's a ToString()
- * here which also fails with TypeError so no explicit check
- * is needed.
+ * in duk_concat_2() which also fails with TypeError so no
+ * explicit check is needed.
*/
- duk_to_string(ctx, -2);
- duk_to_string(ctx, -1);
- duk_concat(ctx, 2); /* [... s1 s2] -> [... s1+s2] */
+ duk_concat_2(thr); /* [... s1 s2] -> [... s1+s2] */
} else {
duk_double_t d1, d2;
- d1 = duk_to_number_m2(ctx);
- d2 = duk_to_number_m1(ctx);
- DUK_ASSERT(duk_is_number(ctx, -2));
- DUK_ASSERT(duk_is_number(ctx, -1));
+ d1 = duk_to_number_m2(thr);
+ d2 = duk_to_number_m1(thr);
+ DUK_ASSERT(duk_is_number(thr, -2));
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
du.d = d1 + d2;
- duk_pop_2(ctx);
- duk_push_number(ctx, du.d); /* will NaN normalize result */
+ duk_pop_2_unsafe(thr);
+ duk_push_number(thr, du.d); /* will NaN normalize result */
}
- duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
+ duk_replace(thr, (duk_idx_t) idx_z); /* side effects */
}
-DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_idx_t idx_z, duk_small_uint_fast_t opcode) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_uint_fast_t idx_z, duk_small_uint_fast_t opcode) {
/*
* Arithmetic operations other than '+' have number-only semantics
* and are implemented here. The separate switch-case here means a
@@ -70503,7 +72035,6 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tv
* E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
*/
- duk_context *ctx = (duk_context *) thr;
duk_double_t d1, d2;
duk_double_union du;
duk_small_uint_fast_t opcode_shifted;
@@ -70512,11 +72043,10 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tv
#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_x != NULL); /* may be reg or const */
DUK_ASSERT(tv_y != NULL); /* may be reg or const */
DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
+ DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
@@ -70539,8 +72069,8 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tv
* 32-bit inputs. Avoid zero inputs to avoid
* negative zero issues (-1 * 0 = -0, for instance).
*/
- if (v1 >= -0x80000000LL && v1 <= 0x7fffffffLL && v1 != 0 &&
- v2 >= -0x80000000LL && v2 <= 0x7fffffffLL && v2 != 0) {
+ if (v1 >= DUK_I64_CONSTANT(-0x80000000) && v1 <= DUK_I64_CONSTANT(0x7fffffff) && v1 != 0 &&
+ v2 >= DUK_I64_CONSTANT(-0x80000000) && v2 <= DUK_I64_CONSTANT(0x7fffffff) && v2 != 0) {
v3 = v1 * v2;
} else {
goto skip_fastint;
@@ -70583,7 +72113,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tv
}
v3_hi = (duk_int32_t) (v3 >> 32);
- if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
+ if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
return;
@@ -70598,15 +72128,15 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tv
d1 = DUK_TVAL_GET_NUMBER(tv_x);
d2 = DUK_TVAL_GET_NUMBER(tv_y);
} else {
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- d1 = duk_to_number_m2(ctx); /* side effects */
- d2 = duk_to_number_m1(ctx);
- DUK_ASSERT(duk_is_number(ctx, -2));
- DUK_ASSERT(duk_is_number(ctx, -1));
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ d1 = duk_to_number_m2(thr); /* side effects */
+ d2 = duk_to_number_m1(thr);
+ DUK_ASSERT(duk_is_number(thr, -2));
+ DUK_ASSERT(duk_is_number(thr, -1));
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
}
switch (opcode_shifted) {
@@ -70640,8 +72170,8 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tv
}
#if defined(DUK_USE_EXEC_PREFER_SIZE)
- duk_push_number(ctx, du.d); /* will NaN normalize result */
- duk_replace(ctx, idx_z);
+ duk_push_number(thr, du.d); /* will NaN normalize result */
+ duk_replace(thr, (duk_idx_t) idx_z);
#else /* DUK_USE_EXEC_PREFER_SIZE */
/* important to use normalized NaN with 8-byte tagged types */
DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
@@ -70662,7 +72192,6 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_
* E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
*/
- duk_context *ctx = (duk_context *) thr;
duk_int32_t i1, i2, i3;
duk_uint32_t u1, u2, u3;
#if defined(DUK_USE_FASTINT)
@@ -70676,11 +72205,10 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_
#endif
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(tv_x != NULL); /* may be reg or const */
DUK_ASSERT(tv_y != NULL); /* may be reg or const */
DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
+ DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
@@ -70692,11 +72220,11 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_
else
#endif /* DUK_USE_FASTINT */
{
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- i1 = duk_to_int32(ctx, -2);
- i2 = duk_to_int32(ctx, -1);
- duk_pop_2(ctx);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ i1 = duk_to_int32(thr, -2);
+ i2 = duk_to_int32(thr, -1);
+ duk_pop_2_unsafe(thr);
}
switch (opcode_shifted) {
@@ -70771,8 +72299,8 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_
DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */
#if defined(DUK_USE_EXEC_PREFER_SIZE)
- duk_push_number(ctx, d3); /* would NaN normalize result, but unnecessary */
- duk_replace(ctx, idx_z);
+ duk_push_number(thr, d3); /* would NaN normalize result, but unnecessary */
+ duk_replace(thr, (duk_idx_t) idx_z);
#else /* DUK_USE_EXEC_PREFER_SIZE */
tv_z = thr->valstack_bottom + idx_z;
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */
@@ -70781,7 +72309,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_
}
/* In-place unary operation. */
-DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx_t idx_src, duk_idx_t idx_dst, duk_small_uint_fast_t opcode) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst, duk_small_uint_fast_t opcode) {
/*
* Arithmetic operations other than '+' have number-only semantics
* and are implemented here. The separate switch-case here means a
@@ -70790,18 +72318,16 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx
* E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
*/
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv;
duk_double_t d1;
duk_double_union du;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(opcode == DUK_OP_UNM || opcode == DUK_OP_UNP);
- DUK_ASSERT(idx_src >= 0);
- DUK_ASSERT(idx_dst >= 0);
+ DUK_ASSERT_DISABLE(idx_src >= 0);
+ DUK_ASSERT_DISABLE(idx_dst >= 0);
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_src);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv)) {
@@ -70815,7 +72341,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx
*/
if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
v2 = -v1;
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
return;
}
@@ -70823,7 +72349,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx
/* ToNumber() for a fastint is a no-op. */
DUK_ASSERT(opcode == DUK_OP_UNP);
v2 = v1;
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
return;
}
@@ -70834,8 +72360,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx
if (DUK_TVAL_IS_NUMBER(tv)) {
d1 = DUK_TVAL_GET_NUMBER(tv);
} else {
- d1 = duk_to_number(ctx, idx_src); /* side effects, perform in-place */
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(DUK_GET_TVAL_POSIDX(ctx, idx_src)));
+ d1 = duk_to_number_tval(thr, tv); /* side effects */
}
if (opcode == DUK_OP_UNP) {
@@ -70845,7 +72370,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx
du.d = d1;
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
#if defined(DUK_USE_FASTINT)
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); /* always 'fast', i.e. inlined */
return;
#endif
@@ -70857,7 +72382,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx
}
/* XXX: size optimize: push+replace? */
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, du.d);
}
@@ -70866,19 +72391,16 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_f
* E5 Section 11.4.8
*/
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv;
duk_int32_t i1, i2;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT_DISABLE(idx_src >= 0);
DUK_ASSERT_DISABLE(idx_dst >= 0);
- DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(ctx));
- DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(ctx));
- DUK_UNREF(thr); /* w/o refcounts */
+ DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
+ DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_src);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
#if defined(DUK_USE_FASTINT)
if (DUK_TVAL_IS_FASTINT(tv)) {
@@ -70887,48 +72409,46 @@ DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_f
else
#endif /* DUK_USE_FASTINT */
{
- i1 = duk_to_int32(ctx, idx_src); /* side effects */
+ duk_push_tval(thr, tv);
+ i1 = duk_to_int32(thr, -1); /* side effects */
+ duk_pop_unsafe(thr);
}
/* Result is always fastint compatible. */
i2 = ~i1;
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
DUK_TVAL_SET_I32_UPDREF(thr, tv, i2); /* side effects */
}
-DUK_LOCAL DUK__INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_idx_t idx_src, duk_idx_t idx_dst) {
+DUK_LOCAL DUK__INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
/*
* E5 Section 11.4.9
*/
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv;
duk_bool_t res;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT_DISABLE(idx_src >= 0);
DUK_ASSERT_DISABLE(idx_dst >= 0);
- DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(ctx));
- DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(ctx));
- DUK_UNREF(thr); /* w/o refcounts */
+ DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
+ DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
/* ToBoolean() does not require any operations with side effects so
* we can do it efficiently. For footprint it would be better to use
* duk_js_toboolean() and then push+replace to the result slot.
*/
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_src);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
res = duk_js_toboolean(tv); /* does not modify 'tv' */
DUK_ASSERT(res == 0 || res == 1);
res ^= 1;
- tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
+ tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
/* XXX: size optimize: push+replace? */
DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, res); /* side effects */
}
/* XXX: size optimized variant */
DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_small_uint_t op) {
- duk_context *ctx = (duk_context *) thr;
duk_double_t x, y, z;
/* Two lowest bits of opcode are used to distinguish
@@ -70987,15 +72507,15 @@ DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr,
bc = (duk_idx_t) (tv_src - thr->valstack_bottom); /* XXX: pass index explicitly? */
tv_src = NULL; /* no longer referenced */
- x = duk_to_number(ctx, bc);
+ x = duk_to_number(thr, bc);
if (op & 0x01) {
y = x - 1.0;
} else {
y = x + 1.0;
}
- duk_push_number(ctx, y);
- duk_replace(ctx, bc);
+ duk_push_number(thr, y);
+ duk_replace(thr, bc);
tv_dst = (duk_tval *) (void *) (((duk_uint8_t *) thr->valstack_bottom) + off_dst);
}
@@ -71004,8 +72524,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr,
DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); /* side effects */
}
-DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr, duk_small_uint_t idx_dst, duk_tval *tv_id, duk_small_uint_t op, duk_uint_t is_strict) {
- duk_context *ctx = (duk_context *) thr;
+DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr, duk_small_uint_t idx_dst, duk_tval *tv_id, duk_small_uint_t op, duk_small_uint_t is_strict) {
duk_activation *act;
duk_double_t x, y;
duk_hstring *name;
@@ -71038,7 +72557,7 @@ DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr,
* not intuitive.
*/
- x = duk_to_number_m2(ctx);
+ x = duk_to_number_m2(thr);
if (op & 0x01) {
y = x - 1.0;
} else {
@@ -71048,21 +72567,21 @@ DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr,
/* [... x this] */
if (op & 0x02) {
- duk_push_number(ctx, y); /* -> [ ... x this y ] */
- act = thr->callstack_curr;
- duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict);
- duk_pop_2(ctx); /* -> [ ... x ] */
+ duk_push_number(thr, y); /* -> [ ... x this y ] */
+ DUK_ASSERT(act == thr->callstack_curr);
+ duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
+ duk_pop_2_unsafe(thr); /* -> [ ... x ] */
} else {
- duk_pop_2(ctx); /* -> [ ... ] */
- duk_push_number(ctx, y); /* -> [ ... y ] */
- act = thr->callstack_curr;
- duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict);
+ duk_pop_2_unsafe(thr); /* -> [ ... ] */
+ duk_push_number(thr, y); /* -> [ ... y ] */
+ DUK_ASSERT(act == thr->callstack_curr);
+ duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
}
#if defined(DUK_USE_EXEC_PREFER_SIZE)
- duk_replace(ctx, (duk_idx_t) idx_dst);
+ duk_replace(thr, (duk_idx_t) idx_dst);
#else /* DUK_USE_EXEC_PREFER_SIZE */
- DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(ctx, idx_dst));
+ DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst));
#endif /* DUK_USE_EXEC_PREFER_SIZE */
}
@@ -71087,119 +72606,118 @@ DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr,
* top are combined into one pass.
*/
-/* Reconfigure value stack for return to an Ecmascript function at 'act_idx'. */
-DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr, duk_size_t act_idx) {
+/* Reconfigure value stack for return to an Ecmascript function at
+ * callstack top (caller unwinds).
+ */
+DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) {
duk_activation *act;
duk_hcompfunc *h_func;
duk_idx_t clamp_top;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
- DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
/* Clamp so that values at 'clamp_top' and above are wiped and won't
* retain reachable garbage. Then extend to 'nregs' because we're
* returning to an Ecmascript function.
*/
- act = thr->callstack + act_idx;
h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
- thr->valstack_bottom = thr->valstack + act->idx_bottom;
- DUK_ASSERT(act->idx_retval >= act->idx_bottom);
- clamp_top = (duk_idx_t) (act->idx_retval - act->idx_bottom + 1); /* +1 = one retval */
- duk_set_top((duk_context *) thr, clamp_top);
- act = NULL;
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
+ DUK_ASSERT(act->retval_byteoff >= act->bottom_byteoff);
+ clamp_top = (duk_idx_t) ((act->retval_byteoff - act->bottom_byteoff + sizeof(duk_tval)) / sizeof(duk_tval)); /* +1 = one retval */
+ duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
- (void) duk_valstack_resize_raw((duk_context *) thr,
- (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- h_func->nregs + /* reg count */
- DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
- duk_set_top((duk_context *) thr, h_func->nregs);
+ /* XXX: a best effort shrink check would be OK here */
}
-DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_size_t act_idx, duk_size_t cat_idx) {
- duk_activation *act;
+/* Reconfigure value stack for an Ecmascript catcher. Use topmost catcher
+ * in 'act'.
+ */
+DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_activation *act) {
duk_catcher *cat;
duk_hcompfunc *h_func;
+ duk_size_t idx_bottom;
duk_idx_t clamp_top;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
- DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
- act = thr->callstack + act_idx;
- cat = thr->catchstack + cat_idx;
h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
- thr->valstack_bottom = thr->valstack + act->idx_bottom;
- DUK_ASSERT(cat->idx_base >= act->idx_bottom);
- clamp_top = (duk_idx_t) (cat->idx_base - act->idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
- duk_set_top((duk_context *) thr, clamp_top);
- act = NULL;
- cat = NULL;
+ thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
+ idx_bottom = (duk_size_t) (thr->valstack_bottom - thr->valstack);
+ DUK_ASSERT(cat->idx_base >= idx_bottom);
+ clamp_top = (duk_idx_t) (cat->idx_base - idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
+ duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
- (void) duk_valstack_resize_raw((duk_context *) thr,
- (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- h_func->nregs + /* reg count */
- DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
+ thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
- duk_set_top((duk_context *) thr, h_func->nregs);
+ /* XXX: a best effort shrink check would be OK here */
}
-/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. */
-DUK_LOCAL void duk__set_catcher_regs(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
+/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type.
+ * No side effects.
+ */
+DUK_LOCAL void duk__set_catcher_regs_norz(duk_hthread *thr, duk_catcher *cat, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
duk_tval *tv1;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base;
+ tv1 = thr->valstack + cat->idx_base;
DUK_ASSERT(tv1 < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
+ DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr, tv1, tv_val_unstable);
- tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base + 1;
+ tv1++;
+ DUK_ASSERT(tv1 == thr->valstack + cat->idx_base + 1);
DUK_ASSERT(tv1 < thr->valstack_top);
-
- DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) lj_type); /* side effects */
+ DUK_TVAL_SET_U32_UPDREF_NORZ(thr, tv1, (duk_uint32_t) lj_type);
}
-DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
- duk_context *ctx;
+DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- ctx = (duk_context *) thr;
- duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
- duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1);
- duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1);
+ duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
DUK_ASSERT(thr->callstack_top >= 1);
DUK_ASSERT(thr->callstack_curr != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
- duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ duk__reconfig_valstack_ecma_catcher(thr, act);
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack_curr;
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
- act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */
- act = NULL;
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+
+ act->curr_pc = cat->pc_base + 0; /* +0 = catch */
/*
* If entering a 'catch' block which requires an automatic
@@ -71211,31 +72729,26 @@ DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval
* which implies the binding is not deletable.
*/
- if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) {
+ if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)) {
duk_hdecenv *new_env;
DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding"));
- /* Note: 'act' is dangerous here because it may get invalidate at many
- * points, so we re-lookup it multiple times.
- */
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack_curr;
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
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_curr;
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
}
DUK_ASSERT(act->lex_env != NULL);
DUK_ASSERT(act->var_env != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_UNREF(act); /* unreferenced without assertions */
/* XXX: If an out-of-memory happens here, longjmp state asserts
* will be triggered at present and a try-catch fails to catch.
@@ -71247,7 +72760,7 @@ DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
- duk_push_hobject(ctx, (duk_hobject *) new_env);
+ duk_push_hobject(thr, (duk_hobject *) new_env);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
@@ -71258,12 +72771,12 @@ DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval
*/
/* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */
- DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL);
- duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname);
- duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base);
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
+ DUK_ASSERT(cat->h_varname != NULL);
+ duk_push_hstring(thr, cat->h_varname);
+ duk_push_tval(thr, thr->valstack + cat->idx_base);
+ duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
- act = thr->callstack_curr;
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env);
act->lex_env = (duk_hobject *) new_env;
@@ -71272,66 +72785,74 @@ DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval
* prototype, decref for act->lex_env overwrite.
*/
- DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]);
+ DUK_CAT_SET_LEXENV_ACTIVE(cat);
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
}
- DUK_CAT_CLEAR_CATCH_ENABLED(&thr->catchstack[cat_idx]);
+ DUK_CAT_CLEAR_CATCH_ENABLED(cat);
}
-DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
+DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ DUK_ASSERT(act->cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
- duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */
- duk_hthread_callstack_unwind_norz(thr, thr->catchstack[cat_idx].callstack_index + 1);
+ duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
DUK_ASSERT(thr->callstack_top >= 1);
DUK_ASSERT(thr->callstack_curr != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
- duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ duk__reconfig_valstack_ecma_catcher(thr, act);
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack_curr;
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
- act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */
- act = NULL;
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+
+ act->curr_pc = cat->pc_base + 1; /* +1 = finally */
- DUK_CAT_CLEAR_FINALLY_ENABLED(&thr->catchstack[cat_idx]);
+ DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
}
-DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_size_t cat_idx, duk_small_uint_t lj_type) {
+DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_small_uint_t lj_type) {
duk_activation *act;
+ duk_catcher *cat;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->callstack_top >= 1);
act = thr->callstack_curr;
DUK_ASSERT(act != NULL);
-
DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
/* +0 = break, +1 = continue */
- act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
- act = NULL; /* invalidated */
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
- duk_hthread_catchstack_unwind_norz(thr, cat_idx + 1); /* keep label catcher */
- /* no need to unwind callstack */
+ act->curr_pc = cat->pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
/* valstack should not need changes */
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack_curr;
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
(duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs);
@@ -71340,41 +72861,35 @@ DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_size_t cat_idx, duk_small
/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
* when a RETURN opcode terminates a thread and yields to the resumer.
+ * Caller unwinds so that top of callstack is the activation we return to.
*/
#if defined(DUK_USE_COROUTINE_SUPPORT)
-DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_size_t act_idx, duk_tval *tv_val_unstable) {
+DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_tval *tv_val_unstable) {
+ duk_activation *act_resumer;
duk_tval *tv1;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(resumer != NULL);
DUK_ASSERT(tv_val_unstable != NULL);
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack + act_idx))); /* resume caller must be an ecmascript func */
+ act_resumer = resumer->callstack_curr;
+ DUK_ASSERT(act_resumer != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(act_resumer) != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer))); /* resume caller must be an ecmascript func */
- tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
+ tv1 = (duk_tval *) (void *) ((duk_uint8_t *) resumer->valstack + act_resumer->retval_byteoff); /* return value from Duktape.Thread.resume() */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ /* XXX: avoid side effects */
- duk_hthread_callstack_unwind_norz(resumer, act_idx + 1); /* unwind to 'resume' caller */
-
- /* no need to unwind catchstack */
- duk__reconfig_valstack_ecma_return(resumer, act_idx);
+ duk__reconfig_valstack_ecma_return(resumer);
/* caller must change active thread, and set thr->resumer to NULL */
}
#endif /* DUK_USE_COROUTINE_SUPPORT */
-DUK_LOCAL
-duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top) {
- duk_size_t entry_callstack_index;
+DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation *entry_act) {
duk_small_uint_t retval = DUK__LONGJMP_RESTART;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(entry_thread != NULL);
- DUK_ASSERT(entry_callstack_top > 0); /* guarantees entry_callstack_top - 1 >= 0 */
-
- entry_callstack_index = entry_callstack_top - 1;
+ DUK_ASSERT(entry_act != NULL);
/* 'thr' is the current thread, as no-one resumes except us and we
* switch 'thr' in that case.
@@ -71410,7 +72925,6 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
duk_tval *tv;
duk_tval *tv2;
- duk_size_t act_idx;
duk_hthread *resumee;
/* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
@@ -71418,10 +72932,10 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */
DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume);
- DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */
tv = &thr->heap->lj.value2; /* resumee */
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
@@ -71439,8 +72953,6 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
(DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL &&
DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) &&
((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield));
- DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- (resumee->callstack_curr - 1)->idx_retval >= 0); /* idx_retval unsigned */
DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */
@@ -71473,19 +72985,28 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
goto check_longjmp;
} else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
- act_idx = resumee->callstack_top - 2; /* Ecmascript function */
- DUK_ASSERT_DISABLE(resumee->callstack[act_idx].idx_retval >= 0); /* unsigned */
+ /* Unwind previous Duktape.Thread.yield() call. The
+ * activation remaining must always be an Ecmascript
+ * call now (yield() accepts calls from Ecmascript
+ * only).
+ */
+ duk_activation *act_resumee;
+
+ DUK_ASSERT(resumee->callstack_top >= 2);
+ act_resumee = resumee->callstack_curr; /* Duktape.Thread.yield() */
+ DUK_ASSERT(act_resumee != NULL);
+ act_resumee = act_resumee->parent; /* Ecmascript call site for yield() */
+ DUK_ASSERT(act_resumee != NULL);
- tv = resumee->valstack + resumee->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.yield() */
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) resumee->valstack + act_resumee->retval_byteoff); /* return value from Duktape.Thread.yield() */
DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
tv2 = &thr->heap->lj.value1;
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ /* XXX: avoid side effects */
- duk_hthread_callstack_unwind_norz(resumee, act_idx + 1); /* unwind to 'yield' caller */
+ duk_hthread_activation_unwind_norz(resumee); /* unwind to 'yield' caller */
+ /* no need to unwind catch stack */
- /* no need to unwind catchstack */
-
- duk__reconfig_valstack_ecma_return(resumee, act_idx);
+ duk__reconfig_valstack_ecma_return(resumee);
DUK_ASSERT(resumee->resumer == NULL);
resumee->resumer = thr;
@@ -71500,22 +73021,21 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
retval = DUK__LONGJMP_RESTART;
goto wipe_and_return;
} else {
+ /* Initial resume call. */
duk_small_uint_t call_flags;
- duk_bool_t setup_rc;
+ duk_int_t setup_rc;
/* resumee: [... initial_func] (currently actually: [initial_func]) */
- duk_push_undefined((duk_context *) resumee);
+ duk_push_undefined(resumee);
tv = &thr->heap->lj.value1;
- duk_push_tval((duk_context *) resumee, tv);
+ duk_push_tval(resumee, tv);
/* resumee: [... initial_func undefined(= this) resume_value ] */
- call_flags = DUK_CALL_FLAG_IS_RESUME; /* is resume, not a tail call */
+ call_flags = DUK_CALL_FLAG_ALLOW_ECMATOECMA; /* not tailcall, ecma-to-ecma (assumed to succeed) */
- setup_rc = duk_handle_ecma_call_setup(resumee,
- 1, /* num_stack_args */
- call_flags); /* call_flags */
+ setup_rc = duk_handle_call_unprotected_nargs(resumee, 1 /*nargs*/, call_flags);
if (setup_rc == 0) {
/* This shouldn't happen; Duktape.Thread.resume()
* should make sure of that. If it does happen
@@ -71557,16 +73077,18 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
/* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
+#if 0 /* entry_thread not available for assert */
DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */
+#endif
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */
DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */
DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr - 1) != NULL &&
- DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->callstack_curr - 1)->idx_retval >= 0); /* unsigned */
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* an Ecmascript function */
resumer = thr->resumer;
@@ -71574,12 +73096,12 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */
DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
DUK_ASSERT(resumer->callstack_curr != NULL);
+ DUK_ASSERT(resumer->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL &&
DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) &&
((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume);
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1) != NULL &&
- DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr - 1))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */
+ DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent))); /* an Ecmascript function */
if (thr->heap->lj.iserror) {
thr->state = DUK_HTHREAD_STATE_YIELDED;
@@ -71596,7 +73118,8 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
goto check_longjmp;
} else {
- duk__handle_yield(thr, resumer, resumer->callstack_top - 2, &thr->heap->lj.value1);
+ duk_hthread_activation_unwind_norz(resumer);
+ duk__handle_yield(thr, resumer, &thr->heap->lj.value1);
thr->state = DUK_HTHREAD_STATE_YIELDED;
thr->resumer = NULL;
@@ -71635,77 +73158,75 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
* Ecmascript activations.
*/
+ duk_activation *act;
duk_catcher *cat;
duk_hthread *resumer;
- cat = thr->catchstack + thr->catchstack_top - 1;
- while (cat >= thr->catchstack) {
- if (thr == entry_thread &&
- cat->callstack_index < entry_callstack_index) {
- /* entry level reached */
+ for (;;) {
+ act = thr->callstack_curr;
+ if (act == NULL) {
break;
}
- if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
+ for (;;) {
+ cat = act->cat;
+ if (cat == NULL) {
+ break;
+ }
+
+ if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
+ DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
- duk__handle_catch(thr,
- cat - thr->catchstack,
- &thr->heap->lj.value1,
- DUK_LJ_TYPE_THROW);
+ duk__handle_catch(thr,
+ &thr->heap->lj.value1,
+ DUK_LJ_TYPE_THROW);
- DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- }
+ DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
+ retval = DUK__LONGJMP_RESTART;
+ goto wipe_and_return;
+ }
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
- DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
+ if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
+ DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
+ DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
- duk__handle_finally(thr,
- cat - thr->catchstack,
- &thr->heap->lj.value1,
- DUK_LJ_TYPE_THROW);
+ duk__handle_finally(thr,
+ &thr->heap->lj.value1,
+ DUK_LJ_TYPE_THROW);
- DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
+ DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
+ retval = DUK__LONGJMP_RESTART;
+ goto wipe_and_return;
+ }
+
+ duk_hthread_catcher_unwind_norz(thr, act);
}
- cat--;
- }
+ if (act == entry_act) {
+ /* Not caught by anything before entry level; rethrow and let the
+ * final catcher finish unwinding (esp. value stack).
+ */
+ DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
+ retval = DUK__LONGJMP_RETHROW;
+ goto just_return;
+ }
- if (thr == entry_thread) {
- /* not caught by anything before entry level; rethrow and let the
- * final catcher unwind everything
- */
-#if 0
- duk_hthread_catchstack_unwind_norz(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
- duk_hthread_callstack_unwind_norz(thr, entry_callstack_index + 1);
- DUK_REFZERO_CHECK_SLOW(thr);
-#endif
- DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
- retval = DUK__LONGJMP_RETHROW;
- goto just_return;
- /* Note: MUST NOT wipe_and_return here, as heap->lj must remain intact */
+ duk_hthread_activation_unwind_norz(thr);
}
DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
- /* not caught by current thread, thread terminates (yield error to resumer);
+ /* Not caught by current thread, thread terminates (yield error to resumer);
* note that this may cause a cascade if the resumer terminates with an uncaught
- * exception etc (this is OK, but needs careful testing)
+ * exception etc (this is OK, but needs careful testing).
*/
DUK_ASSERT(thr->resumer != NULL);
DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
DUK_ASSERT(thr->resumer->callstack_curr != NULL);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL &&
- DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) &&
- ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL &&
- DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */
+ DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */
resumer = thr->resumer;
@@ -71766,70 +73287,61 @@ duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
* handling because it has a measurable performance impact in ordinary
* environments and an extreme impact in Emscripten (GH-342).
*/
-DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
- duk_uint_t label_id,
- duk_small_uint_t lj_type) {
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_break_or_continue(duk_hthread *thr,
+ duk_uint_t label_id,
+ duk_small_uint_t lj_type) {
+ duk_activation *act;
duk_catcher *cat;
- duk_size_t orig_callstack_index;
DUK_ASSERT(thr != NULL);
- /*
- * Find a matching label catcher or 'finally' catcher in
- * the same function.
+ /* Find a matching label catcher or 'finally' catcher in
+ * the same function, unwinding catchers as we go.
*
- * A label catcher must always exist and will match unless
- * a 'finally' captures the break/continue first. It is the
- * compiler's responsibility to ensure that labels are used
- * correctly.
- */
-
- /* Note: thr->catchstack_top may be 0, so that cat < thr->catchstack
- * initially. This is OK and intended.
+ * A label catcher must always exist and will match unless
+ * a 'finally' captures the break/continue first. It is the
+ * compiler's responsibility to ensure that labels are used
+ * correctly.
*/
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_ASSERT(thr->callstack_top > 0);
- orig_callstack_index = thr->callstack_top - 1;
- DUK_DDD(DUK_DDDPRINT("handling break/continue with label=%ld, callstack index=%ld",
- (long) label_id, (long) cat->callstack_index));
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
- while (cat >= thr->catchstack) {
- if (cat->callstack_index != orig_callstack_index) {
+ for (;;) {
+ cat = act->cat;
+ if (cat == NULL) {
break;
}
- DUK_DDD(DUK_DDDPRINT("considering catcher %ld: type=%ld label=%ld",
- (long) (cat - thr->catchstack),
+
+ DUK_DDD(DUK_DDDPRINT("considering catcher %p: type=%ld label=%ld",
+ (void *) cat,
(long) DUK_CAT_GET_TYPE(cat),
(long) DUK_CAT_GET_LABEL(cat)));
+ /* XXX: bit mask test; FINALLY <-> TCF, single bit mask would suffice? */
+
if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- duk_size_t cat_idx;
duk_tval tv_tmp;
- cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
-
DUK_TVAL_SET_U32(&tv_tmp, (duk_uint32_t) label_id);
- duk__handle_finally(thr, cat_idx, &tv_tmp, lj_type);
+ duk__handle_finally(thr, &tv_tmp, lj_type);
DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
return;
}
if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
(duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
- duk_size_t cat_idx;
-
- cat_idx = (duk_size_t) (cat - thr->catchstack);
- duk__handle_label(thr, cat_idx, lj_type);
+ duk__handle_label(thr, lj_type);
DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
return;
}
- cat--;
+
+ duk_hthread_catcher_unwind_norz(thr, act);
}
- /* should never happen, but be robust */
+ /* Should never happen, but be robust. */
DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
DUK_ERROR_INTERNAL(thr);
return;
@@ -71839,22 +73351,19 @@ DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
* it has a measurable performance impact in ordinary environments and an extreme
* impact in Emscripten (GH-342). Return value is on value stack top.
*/
-DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top) {
+DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation *entry_act) {
duk_tval *tv1;
duk_tval *tv2;
#if defined(DUK_USE_COROUTINE_SUPPORT)
duk_hthread *resumer;
#endif
+ duk_activation *act;
duk_catcher *cat;
- duk_size_t new_cat_top;
- duk_size_t orig_callstack_index;
/* We can directly access value stack here. */
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(entry_thread != NULL);
+ DUK_ASSERT(entry_act != NULL);
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
tv1 = thr->valstack_top - 1;
DUK_TVAL_CHKFAST_INPLACE_FAST(tv1); /* fastint downgrade check for return values */
@@ -71882,78 +73391,69 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack != NULL);
-
- /* XXX: does not work if thr->catchstack is NULL */
- /* XXX: does not work if thr->catchstack is allocated but lowest pointer */
- cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */
- DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */
- DUK_ASSERT(thr->callstack_curr != NULL);
- orig_callstack_index = thr->callstack_top - 1;
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
- while (cat >= thr->catchstack) {
- if (cat->callstack_index != orig_callstack_index) {
+ for (;;) {
+ cat = act->cat;
+ if (cat == NULL) {
break;
}
+
if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- duk_size_t cat_idx;
-
- cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
-
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- duk__handle_finally(thr, cat_idx, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
+ duk__handle_finally(thr, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
return DUK__RETHAND_RESTART;
}
- cat--;
- }
- /* If out of catchstack, cat = thr->catchstack - 1;
- * new_cat_top will be 0 in that case.
- */
- new_cat_top = (duk_size_t) ((cat + 1) - thr->catchstack);
- cat = NULL; /* avoid referencing, invalidated */
- DUK_DDD(DUK_DDDPRINT("no catcher in catch stack, return to calling activation / yield"));
+ duk_hthread_catcher_unwind_norz(thr, act);
+ }
- if (thr == entry_thread &&
- thr->callstack_top == entry_callstack_top) {
- /* Return to the bytecode executor caller which will unwind stacks.
+ if (act == entry_act) {
+ /* Return to the bytecode executor caller who will unwind stacks
+ * and handle constructor post-processing.
* Return value is already on the stack top: [ ... retval ].
*/
- /* XXX: could unwind catchstack here, so that call handling
- * didn't need to do that?
- */
DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
return DUK__RETHAND_FINISHED;
}
if (thr->callstack_top >= 2) {
/* There is a caller; it MUST be an Ecmascript caller (otherwise it would
- * match entry level check)
+ * match entry_act check).
*/
-
- DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T",
- (long) (thr->callstack_curr - 1)->idx_retval,
+ DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, retval_byteoff=%ld, lj_value1=%!T",
+ (long) (thr->callstack_curr->parent->retval_byteoff),
(duk_tval *) &thr->heap->lj.value1));
- DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr - 1))); /* must be ecmascript */
+ DUK_ASSERT(thr->callstack_curr != NULL);
+ DUK_ASSERT(thr->callstack_curr->parent != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* must be ecmascript */
+
+#if defined(DUK_USE_ES6_PROXY)
+ if (thr->callstack_curr->flags & (DUK_ACT_FLAG_CONSTRUCT | DUK_ACT_FLAG_CONSTRUCT_PROXY)) {
+ duk_call_construct_postprocess(thr, thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY); /* side effects */
+ }
+#else
+ if (thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT) {
+ duk_call_construct_postprocess(thr, 0); /* side effects */
+ }
+#endif
- tv1 = thr->valstack + (thr->callstack_curr - 1)->idx_retval;
+ tv1 = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + thr->callstack_curr->parent->retval_byteoff);
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
tv2 = thr->valstack_top - 1;
DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T",
- (long) (thr->callstack_curr - 1)->idx_retval,
- (duk_tval *) (thr->valstack + (thr->callstack_curr - 1)->idx_retval)));
+ /* Catch stack unwind happens inline in callstack unwind. */
+ duk_hthread_activation_unwind_norz(thr);
- duk_hthread_catchstack_unwind_norz(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
- duk_hthread_callstack_unwind_norz(thr, thr->callstack_top - 1);
- duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1);
+ duk__reconfig_valstack_ecma_return(thr);
DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
return DUK__RETHAND_RESTART;
@@ -71965,12 +73465,12 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
DUK_ASSERT(thr->resumer != NULL);
DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
DUK_ASSERT(thr->resumer->callstack_curr != NULL);
+ DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL &&
- DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) &&
- ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1) != NULL &&
- DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr - 1))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->resumer->callstack_curr - 1)->idx_retval >= 0); /* unsigned */
+ DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) &&
+ ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
+ DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
+ DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an Ecmascript function */
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
@@ -71978,7 +73478,8 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
/* Share yield longjmp handler. */
DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- duk__handle_yield(thr, resumer, resumer->callstack_top - 2, thr->valstack_top - 1);
+ duk_hthread_activation_unwind_norz(resumer);
+ duk__handle_yield(thr, resumer, thr->valstack_top - 1);
duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
@@ -72032,7 +73533,6 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
- duk_context *ctx;
duk_activation *act;
duk_breakpoint *bp;
duk_breakpoint **bp_active;
@@ -72042,7 +73542,6 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */
- ctx = (duk_context *) thr;
act = thr->callstack_curr;
DUK_ASSERT(act != NULL);
@@ -72052,22 +73551,28 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
*/
/*
+ * Single opcode step check
+ */
+
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by one opcode step"));
+ duk_debug_set_paused(thr->heap);
+ }
+
+ /*
* Breakpoint and step state checks
*/
if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
- (thr->heap->dbg_step_thread == thr &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
+ (thr->heap->dbg_pause_act == thr->callstack_curr)) {
line = duk_debug_curr_line(thr);
if (act->prev_line != line) {
/* Stepped? Step out is handled by callstack unwind. */
- if ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
- thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
- (thr->heap->dbg_step_thread == thr) &&
- (thr->heap->dbg_step_csindex == thr->callstack_top - 1) &&
- (line != thr->heap->dbg_step_startline)) {
- DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld",
+ if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
+ (thr->heap->dbg_pause_act == thr->callstack_curr) &&
+ (line != thr->heap->dbg_pause_startline)) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by line change, at line %ld",
(long) line));
duk_debug_set_paused(thr->heap);
}
@@ -72093,7 +73598,7 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
DUK_ASSERT(bp->filename != NULL);
if (act->prev_line != bp->line && line == bp->line) {
- DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld",
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by breakpoint at %!O:%ld",
(duk_heaphdr *) bp->filename, (long) bp->line));
duk_debug_set_paused(thr->heap);
}
@@ -72102,7 +73607,7 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
;
}
- act->prev_line = line;
+ act->prev_line = (duk_uint32_t) line;
}
/*
@@ -72126,7 +73631,8 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
}
/* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
- thr->heap->dbg_exec_counter += thr->interrupt_init;
+ DUK_ASSERT(thr->interrupt_init >= 0);
+ thr->heap->dbg_exec_counter += (duk_uint_t) thr->interrupt_init;
if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
/* Overflow of the execution counter is fine and doesn't break
* anything here.
@@ -72135,12 +73641,14 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
duk_double_t now, diff_last;
thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
- now = DUK_USE_DATE_GET_NOW(ctx);
+ now = duk_time_get_monotonic_time(thr);
diff_last = now - thr->heap->dbg_last_time;
if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
- /* Negative value checked so that a "time jump" works
- * reasonably.
+ /* Monotonic time should not experience time jumps,
+ * but the provider may be missing and we're actually
+ * using Ecmascript time. So, tolerate negative values
+ * so that a time jump works reasonably.
*
* Same interval is now used for status sending and
* peeking.
@@ -72167,7 +73675,6 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
* detaching.
*/
- act = NULL; /* may be changed */
if (process_messages) {
DUK_ASSERT(thr->heap->dbg_processing == 0);
processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
@@ -72183,13 +73690,12 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
*/
if (duk_debug_is_attached(thr->heap)) {
- act = thr->callstack_curr; /* relookup, may have changed */
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
- ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
- thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
- thr->heap->dbg_step_thread == thr &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1) ||
+ (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) ||
+ ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
+ thr->heap->dbg_pause_act == thr->callstack_curr) ||
DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
*out_immediate = 1;
}
@@ -72200,6 +73706,13 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
if (processed_messages) {
DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
*out_interrupt_retval = DUK__INT_RESTART;
+ } else {
+ if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) {
+ /* Set 'pause after one opcode' active only when we're
+ * actually just about to execute code.
+ */
+ thr->heap->dbg_pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE;
+ }
}
} else {
DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
@@ -72207,7 +73720,7 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
-DUK_LOCAL DUK_NOINLINE DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
+DUK_LOCAL DUK__NOINLINE_PERF DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
duk_int_t ctr;
duk_activation *act;
duk_hcompfunc *fun;
@@ -72216,7 +73729,6 @@ DUK_LOCAL DUK_NOINLINE DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hth
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(thr->callstack != NULL);
DUK_ASSERT(thr->callstack_top > 0);
#if defined(DUK_USE_DEBUG)
@@ -72294,8 +73806,7 @@ DUK_LOCAL DUK_NOINLINE DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hth
* detaching (to finish off the pending detach).
*/
duk__interrupt_handle_debugger(thr, &immediate, &retval);
- act = thr->callstack_curr; /* relookup if changed */
- DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
+ DUK_ASSERT(act == thr->callstack_curr);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
@@ -72431,21 +73942,19 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
/* Force pause if we were doing "step into" in another activation. */
- if (thr->heap->dbg_step_thread != NULL &&
- thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO &&
- (thr->heap->dbg_step_thread != thr ||
- thr->heap->dbg_step_csindex != thr->callstack_top - 1)) {
- DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED"));
+ if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) &&
+ thr->heap->dbg_pause_act != thr->callstack_curr) {
+ DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry"));
duk_debug_set_paused(thr->heap);
}
/* Force interrupt right away if we're paused or in "checked mode".
* Step out is handled by callstack unwind.
*/
- if (act->flags & (DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
+ if ((act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ||
- (thr->heap->dbg_step_type != DUK_STEP_TYPE_OUT &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
+ ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
+ thr->heap->dbg_pause_act == thr->callstack_curr)) {
/* We'll need to interrupt early so recompute the init
* counter to reflect the number of bytecode instructions
* executed so that step counts for e.g. debugger rate
@@ -72459,6 +73968,519 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
#endif /* DUK_USE_DEBUGGER_SUPPORT */
/*
+ * Opcode handlers for opcodes with a lot of code and which are relatively
+ * rare; NOINLINE to reduce amount of code in main bytecode dispatcher.
+ */
+
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initset_initget(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_bool_t is_set = (DUK_DEC_OP(ins) == DUK_OP_INITSET);
+ duk_uint_fast_t idx;
+ duk_uint_t defprop_flags;
+
+ /* A -> object register (acts as a source)
+ * BC -> BC+0 contains key, BC+1 closure (value)
+ */
+
+ /* INITSET/INITGET are only used to initialize object literal keys.
+ * There may be a previous propery in ES2015 because duplicate property
+ * names are allowed.
+ */
+
+ /* This could be made more optimal by accessing internals directly. */
+
+ idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
+ duk_dup(thr, (duk_idx_t) (idx + 0)); /* key */
+ duk_dup(thr, (duk_idx_t) (idx + 1)); /* getter/setter */
+ if (is_set) {
+ defprop_flags = DUK_DEFPROP_HAVE_SETTER |
+ DUK_DEFPROP_FORCE |
+ DUK_DEFPROP_SET_ENUMERABLE |
+ DUK_DEFPROP_SET_CONFIGURABLE;
+ } else {
+ defprop_flags = DUK_DEFPROP_HAVE_GETTER |
+ DUK_DEFPROP_FORCE |
+ DUK_DEFPROP_SET_ENUMERABLE |
+ DUK_DEFPROP_SET_CONFIGURABLE;
+ }
+ duk_def_prop(thr, (duk_idx_t) DUK_DEC_A(ins), defprop_flags);
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_trycatch(duk_hthread *thr, duk_uint_fast32_t ins, duk_instr_t *curr_pc) {
+ duk_activation *act;
+ duk_catcher *cat;
+ duk_tval *tv1;
+ duk_small_uint_fast_t a;
+ duk_small_uint_fast_t bc;
+
+ /* A -> flags
+ * BC -> reg_catch; base register for two registers used both during
+ * trycatch setup and when catch is triggered
+ *
+ * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
+ * reg_catch + 0: catch binding variable name (string).
+ * Automatic declarative environment is established for
+ * the duration of the 'catch' clause.
+ *
+ * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
+ * reg_catch + 0: with 'target value', which is coerced to
+ * an object and then used as a bindind object for an
+ * environment record. The binding is initialized here, for
+ * the 'try' clause.
+ *
+ * Note that a TRYCATCH generated for a 'with' statement has no
+ * catch or finally parts.
+ */
+
+ /* XXX: TRYCATCH handling should be reworked to avoid creating
+ * an explicit scope unless it is actually needed (e.g. function
+ * instances or eval is executed inside the catch block). This
+ * rework is not trivial because the compiler doesn't have an
+ * intermediate representation. When the rework is done, the
+ * opcode format can also be made more straightforward.
+ */
+
+ /* XXX: side effect handling is quite awkward here */
+
+ DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
+ "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
+ (long) DUK_DEC_BC(ins),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
+ (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
+ (unsigned long) DUK_DEC_A(ins)));
+
+ a = DUK_DEC_A(ins);
+ bc = DUK_DEC_BC(ins);
+
+ /* Registers 'bc' and 'bc + 1' are written in longjmp handling
+ * and if their previous values (which are temporaries) become
+ * unreachable -and- have a finalizer, there'll be a function
+ * call during error handling which is not supported now (GH-287).
+ * Ensure that both 'bc' and 'bc + 1' have primitive values to
+ * guarantee no finalizer calls in error handling. Scrubbing also
+ * ensures finalizers for the previous values run here rather than
+ * later. Error handling related values are also written to 'bc'
+ * and 'bc + 1' but those values never become unreachable during
+ * error handling, so there's no side effect problem even if the
+ * error value has a finalizer.
+ */
+ duk_dup(thr, (duk_idx_t) bc); /* Stabilize value. */
+ duk_to_undefined(thr, (duk_idx_t) bc);
+ duk_to_undefined(thr, (duk_idx_t) (bc + 1));
+
+ /* Allocate catcher and populate it. Doesn't have to
+ * be fully atomic, but the catcher must be in a
+ * consistent state if side effects (such as finalizer
+ * calls) occur.
+ */
+
+ cat = duk_hthread_catcher_alloc(thr);
+ DUK_ASSERT(cat != NULL);
+
+ cat->flags = DUK_CAT_TYPE_TCF;
+ cat->h_varname = NULL;
+ cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
+ cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
+
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat->parent = act->cat;
+ act->cat = cat;
+
+ if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
+ cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
+ }
+ if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
+ cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
+ }
+ if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
+ DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
+ cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
+ DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
+
+ /* borrowed reference; although 'tv1' comes from a register,
+ * its value was loaded using LDCONST so the constant will
+ * also exist and be reachable.
+ */
+ cat->h_varname = DUK_TVAL_GET_STRING(tv1);
+ } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
+ duk_hobjenv *env;
+ duk_hobject *target;
+
+ /* Delayed env initialization for activation (if needed). */
+ DUK_ASSERT(thr->callstack_top >= 1);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ if (act->lex_env == NULL) {
+ DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
+ DUK_ASSERT(act->var_env == NULL);
+
+ duk_js_init_activation_environment_records_delayed(thr, act);
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
+ }
+ DUK_ASSERT(act->lex_env != NULL);
+ DUK_ASSERT(act->var_env != NULL);
+
+ /* Coerce 'with' target. */
+ target = duk_to_hobject(thr, -1);
+ DUK_ASSERT(target != NULL);
+
+ /* Create an object environment; it is not pushed
+ * so avoid side effects very carefully until it is
+ * referenced.
+ */
+ env = duk_hobjenv_alloc(thr,
+ DUK_HOBJECT_FLAG_EXTENSIBLE |
+ DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
+ DUK_ASSERT(env != NULL);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
+ env->target = target; /* always provideThis=true */
+ DUK_HOBJECT_INCREF(thr, target);
+ env->has_this = 1;
+ DUK_ASSERT_HOBJENV_VALID(env);
+ DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env));
+
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
+ DUK_ASSERT(act->lex_env != NULL);
+ DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env);
+ act->lex_env = (duk_hobject *) env; /* Now reachable. */
+ DUK_HOBJECT_INCREF(thr, (duk_hobject *) env);
+ /* Net refcount change to act->lex_env is 0: incref for env's
+ * prototype, decref for act->lex_env overwrite.
+ */
+
+ /* Set catcher lex_env active (affects unwind)
+ * only when the whole setup is complete.
+ */
+ cat = act->cat; /* XXX: better to relookup? not mandatory because 'cat' is stable */
+ cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
+ } else {
+ ;
+ }
+
+ DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, pc_base=%ld, "
+ "idx_base=%ld, h_varname=%!O",
+ (unsigned long) cat->flags,
+ (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
+
+ duk_pop_unsafe(thr);
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endtry(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_activation *act;
+ duk_catcher *cat;
+ duk_tval *tv1;
+ duk_instr_t *pc_base;
+
+ DUK_UNREF(ins);
+
+ DUK_ASSERT(thr->callstack_top >= 1);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
+
+ DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
+ DUK_CAT_CLEAR_CATCH_ENABLED(cat);
+
+ pc_base = cat->pc_base;
+
+ if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
+ DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
+
+ tv1 = thr->valstack + cat->idx_base;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
+ tv1 = NULL;
+
+ tv1 = thr->valstack + cat->idx_base + 1;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
+ tv1 = NULL;
+
+ DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
+ } else {
+ DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
+
+ duk_hthread_catcher_unwind_norz(thr, act); /* lexenv may be set for 'with' binding */
+ /* no need to unwind callstack */
+ }
+
+ return pc_base + 1; /* new curr_pc value */
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endcatch(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_activation *act;
+ duk_catcher *cat;
+ duk_tval *tv1;
+ duk_instr_t *pc_base;
+
+ DUK_UNREF(ins);
+
+ DUK_ASSERT(thr->callstack_top >= 1);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat = act->cat;
+ DUK_ASSERT(cat != NULL);
+ DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
+
+ if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
+ duk_hobject *prev_env;
+
+ /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
+ DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
+ DUK_ASSERT(act->lex_env != NULL);
+
+ DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
+
+ prev_env = act->lex_env;
+ DUK_ASSERT(prev_env != NULL);
+ act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
+ DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
+ DUK_HOBJECT_INCREF(thr, act->lex_env);
+ DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
+
+ DUK_ASSERT(act == thr->callstack_curr);
+ DUK_ASSERT(act != NULL);
+ }
+
+ pc_base = cat->pc_base;
+
+ if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
+ DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
+
+ tv1 = thr->valstack + cat->idx_base;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
+ tv1 = NULL;
+
+ tv1 = thr->valstack + cat->idx_base + 1;
+ DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
+ DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
+ tv1 = NULL;
+
+ DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
+ } else {
+ DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
+
+ duk_hthread_catcher_unwind_norz(thr, act);
+ /* no need to unwind callstack */
+ }
+
+ return pc_base + 1; /* new curr_pc value */
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_endfin(duk_hthread *thr, duk_uint_fast32_t ins, duk_activation *entry_act) {
+ duk_activation *act;
+ duk_tval *tv1;
+ duk_uint_t reg_catch;
+ duk_small_uint_t cont_type;
+ duk_small_uint_t ret_result;
+
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ DUK_ASSERT(thr->callstack_top >= 1);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ reg_catch = DUK_DEC_ABC(ins);
+
+ /* CATCH flag may be enabled or disabled here; it may be enabled if
+ * the statement has a catch block but the try block does not throw
+ * an error.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
+ (duk_tval *) (thr->valstack_bottom + reg_catch + 0),
+ (duk_tval *) (thr->valstack_bottom + reg_catch + 1)));
+
+ tv1 = thr->valstack_bottom + reg_catch + 1; /* type */
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
+ cont_type = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
+#else
+ cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
+#endif
+
+ tv1--; /* value */
+
+ switch (cont_type) {
+ case DUK_LJ_TYPE_NORMAL: {
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
+ "dismantle catcher, resume execution after ENDFIN"));
+
+ duk_hthread_catcher_unwind_norz(thr, act);
+ /* no need to unwind callstack */
+ return 0; /* restart execution */
+ }
+ case DUK_LJ_TYPE_RETURN: {
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
+ "catcher, handle return, lj.value1=%!T", tv1));
+
+ /* Not necessary to unwind catch stack: return handling will
+ * do it. The finally flag of 'cat' is no longer set. The
+ * catch flag may be set, but it's not checked by return handling.
+ */
+
+ duk_push_tval(thr, tv1);
+ ret_result = duk__handle_return(thr, entry_act);
+ if (ret_result == DUK__RETHAND_RESTART) {
+ return 0; /* restart execution */
+ }
+ DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
+
+ DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
+ return 1; /* exit executor */
+ }
+ case DUK_LJ_TYPE_BREAK:
+ case DUK_LJ_TYPE_CONTINUE: {
+ duk_uint_t label_id;
+ duk_small_uint_t lj_type;
+
+ /* Not necessary to unwind catch stack: break/continue
+ * handling will do it. The finally flag of 'cat' is
+ * no longer set. The catch flag may be set, but it's
+ * not checked by break/continue handling.
+ */
+
+ DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
+#if defined(DUK_USE_FASTINT)
+ DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
+ label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
+#else
+ label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
+#endif
+ lj_type = cont_type;
+ duk__handle_break_or_continue(thr, label_id, lj_type);
+ return 0; /* restart execution */
+ }
+ default: {
+ DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
+ "dismantle catcher, re-throw error",
+ (long) cont_type));
+
+ duk_err_setup_ljstate1(thr, (duk_small_uint_t) cont_type, tv1);
+ /* No debugger Throw notify check on purpose (rethrow). */
+
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+ duk_err_longjmp(thr);
+ DUK_UNREACHABLE();
+ }
+ }
+
+ DUK_UNREACHABLE();
+ return 0;
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initenum(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_small_uint_t b;
+ duk_small_uint_t c;
+
+ /*
+ * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
+ * If called with 'null' or 'undefined', this opcode returns 'null' as
+ * the enumerator, which is special cased in NEXTENUM. This simplifies
+ * the compiler part
+ */
+
+ /* B -> register for writing enumerator object
+ * C -> value to be enumerated (register)
+ */
+ b = DUK_DEC_B(ins);
+ c = DUK_DEC_C(ins);
+
+ if (duk_is_null_or_undefined(thr, (duk_idx_t) c)) {
+ duk_push_null(thr);
+ duk_replace(thr, (duk_idx_t) b);
+ } else {
+ duk_dup(thr, (duk_idx_t) c);
+ duk_to_object(thr, -1);
+ duk_hobject_enumerator_create(thr, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
+ duk_replace(thr, (duk_idx_t) b);
+ }
+}
+
+DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_nextenum(duk_hthread *thr, duk_uint_fast32_t ins) {
+ duk_small_uint_t b;
+ duk_small_uint_t c;
+ duk_small_uint_t pc_skip = 0;
+
+ /*
+ * NEXTENUM checks whether the enumerator still has unenumerated
+ * keys. If so, the next key is loaded to the target register
+ * and the next instruction is skipped. Otherwise the next instruction
+ * will be executed, jumping out of the enumeration loop.
+ */
+
+ /* B -> target register for next key
+ * C -> enum register
+ */
+ b = DUK_DEC_B(ins);
+ c = DUK_DEC_C(ins);
+
+ DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
+ (duk_tval *) duk_get_tval(thr, (duk_idx_t) b),
+ (duk_tval *) duk_get_tval(thr, (duk_idx_t) c)));
+
+ if (duk_is_object(thr, (duk_idx_t) c)) {
+ /* XXX: assert 'c' is an enumerator */
+ duk_dup(thr, (duk_idx_t) c);
+ if (duk_hobject_enumerator_next(thr, 0 /*get_value*/)) {
+ /* [ ... enum ] -> [ ... next_key ] */
+ DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
+ (duk_tval *) duk_get_tval(thr, -1)));
+ pc_skip = 1;
+ } else {
+ /* [ ... enum ] -> [ ... ] */
+ DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
+ thr->valstack_top++;
+ }
+ duk_replace(thr, (duk_idx_t) b);
+ } else {
+ /* 'null' enumerator case -> behave as with an empty enumerator */
+ DUK_ASSERT(duk_is_null(thr, (duk_idx_t) c));
+ DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
+ }
+
+ return pc_skip;
+}
+
+/*
+ * Call handling helpers.
+ */
+
+DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, duk_idx_t nargs, duk_small_uint_t call_flags) {
+ duk_bool_t rc;
+
+ duk_set_top_unsafe(thr, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */
+
+ /* Attempt an Ecma-to-Ecma call setup. If the call
+ * target is (directly or indirectly) Reflect.construct(),
+ * the call may change into a constructor call on the fly.
+ */
+ rc = (duk_bool_t) duk_handle_call_unprotected(thr, idx, call_flags);
+ if (rc != 0) {
+ /* Ecma-to-ecma call possible, may or may not
+ * be a tail call. Avoid C recursion by
+ * reusing current executor instance.
+ */
+ DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
+ /* curr_pc synced by duk_handle_call_unprotected() */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ return rc;
+ } else {
+ /* Call was handled inline. */
+ }
+ DUK_ASSERT(thr->ptr_curr_pc != NULL);
+ return rc;
+}
+
+/*
* Ecmascript bytecode executor.
*
* Resume execution for the current thread from its current activation.
@@ -72493,7 +74515,9 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
#else
#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr))
#endif
-#define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
+
+/* Strict flag. */
+#define DUK__STRICT() ((duk_small_uint_t) DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
/* Reg/const access macros: these are very footprint and performance sensitive
* so modify with care. Arguments are sometimes evaluated multiple times which
@@ -72567,23 +74591,23 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
#endif
#define DUK__SYNC_CURR_PC() do { \
- duk_activation *act; \
- act = thr->callstack_curr; \
- act->curr_pc = curr_pc; \
+ duk_activation *duk__act; \
+ duk__act = thr->callstack_curr; \
+ duk__act->curr_pc = curr_pc; \
} while (0)
#define DUK__SYNC_AND_NULL_CURR_PC() do { \
- duk_activation *act; \
- act = thr->callstack_curr; \
- act->curr_pc = curr_pc; \
+ duk_activation *duk__act; \
+ duk__act = thr->callstack_curr; \
+ duk__act->curr_pc = curr_pc; \
thr->ptr_curr_pc = NULL; \
} while (0)
#if defined(DUK_USE_EXEC_PREFER_SIZE)
-#define DUK__LOOKUP_INDIRECT_INDEX(idx) do { \
- (idx) = (duk_uint_fast_t) duk_get_uint(ctx, (idx)); \
+#define DUK__LOOKUP_INDIRECT(idx) do { \
+ (idx) = (duk_uint_fast_t) duk_get_uint(thr, (duk_idx_t) (idx)); \
} while (0)
#elif defined(DUK_USE_FASTINT)
-#define DUK__LOOKUP_INDIRECT_INDEX(idx) do { \
+#define DUK__LOOKUP_INDIRECT(idx) do { \
duk_tval *tv_ind; \
tv_ind = DUK__REGP((idx)); \
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
@@ -72591,7 +74615,7 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
(idx) = (duk_uint_fast_t) DUK_TVAL_GET_FASTINT_U32(tv_ind); \
} while (0)
#else
-#define DUK__LOOKUP_INDIRECT_INDEX(idx) do { \
+#define DUK__LOOKUP_INDIRECT(idx) do { \
duk_tval *tv_ind; \
tv_ind = DUK__REGP(idx); \
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
@@ -72600,8 +74624,7 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
#endif
DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top,
+ duk_activation *entry_act,
duk_int_t entry_call_recursion_depth,
duk_jmpbuf *entry_jmpbuf_ptr) {
duk_small_uint_t lj_ret;
@@ -72623,7 +74646,7 @@ DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
*/
heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
- lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
+ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_act);
/* Error handling complete, remove side effect protections.
*/
@@ -72657,7 +74680,7 @@ DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
/* Entry level info. */
duk_hthread *entry_thread;
- duk_size_t entry_callstack_top;
+ duk_activation *entry_act;
duk_int_t entry_call_recursion_depth;
duk_jmpbuf *entry_jmpbuf_ptr;
duk_jmpbuf our_jmpbuf;
@@ -72668,6 +74691,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
+ DUK_ASSERT(exec_thr->callstack_curr != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr)));
@@ -72675,7 +74699,8 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
entry_thread = exec_thr;
heap = entry_thread->heap;
- entry_callstack_top = entry_thread->callstack_top;
+ entry_act = entry_thread->callstack_curr;
+ DUK_ASSERT(entry_act != NULL);
entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
@@ -72699,7 +74724,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
#endif
/* Execute bytecode until returned or longjmp(). */
- duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
+ duk__js_execute_bytecode_inner(entry_thread, entry_act);
/* Successful return: restore jmpbuf and return to caller. */
heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
@@ -72714,10 +74739,10 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
DUK_UNREF(exc);
#endif
DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
+ DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
+ entry_act,
entry_call_recursion_depth,
entry_jmpbuf_ptr);
}
@@ -72728,6 +74753,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
what = "unknown";
}
DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
try {
DUK_ASSERT(heap->curr_thread != NULL);
DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
@@ -72735,13 +74761,13 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
DUK_UNREF(exc);
duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
+ entry_act,
entry_call_recursion_depth,
entry_jmpbuf_ptr);
}
} catch (...) {
DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
try {
DUK_ASSERT(heap->curr_thread != NULL);
DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
@@ -72749,8 +74775,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
DUK_UNREF(exc);
duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
+ entry_act,
entry_call_recursion_depth,
entry_jmpbuf_ptr);
}
@@ -72762,7 +74787,7 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
}
/* Inner executor, performance critical. */
-DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) {
+DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act) {
/* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
* Critical for performance. It would be safest to make this volatile,
* but that eliminates performance benefits; aliasing guarantees
@@ -72840,7 +74865,6 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
*
* The following are not assumed to have stable pointers at all:
* - the value stack (registers) of the current thread
- * - the catch stack of the current thread
*
* See execution.rst for discussion.
*/
@@ -72881,9 +74905,9 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
DUK_ASSERT(consts != NULL);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing) {
+ if (DUK_UNLIKELY(duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing)) {
duk__executor_recheck_debugger(thr, act, fun);
- act = thr->callstack_curr; /* relookup after side effects (no side effects currently however) */
+ DUK_ASSERT(act == thr->callstack_curr);
DUK_ASSERT(act != NULL);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
@@ -72897,7 +74921,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
}
DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
- "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, catchstack_top=%ld, "
+ "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, "
"preventcount=%ld",
(void *) thr,
(long) (thr->callstack_top - 1),
@@ -72907,7 +74931,6 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
(long) (thr->callstack_top - 1),
(long) (thr->valstack_bottom - thr->valstack),
(long) (thr->valstack_top - thr->valstack),
- (long) thr->catchstack_top,
(long) thr->callstack_preventcount));
/* Dispatch loop. */
@@ -72933,6 +74956,8 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
/* Trigger at zero or below */
duk_small_uint_t exec_int_ret;
+ DUK_STATS_INC(thr->heap, stats_exec_interrupt);
+
/* Write curr_pc back for the debugger. */
{
duk_activation *act;
@@ -72942,7 +74967,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
act->curr_pc = (duk_instr_t *) curr_pc;
}
- /* Force restart caused by a function return; must recheck
+ /* Forced restart caused by a function return; must recheck
* debugger breakpoints before checking line transitions,
* see GH-303. Restart and then handle interrupt_counter
* zero again.
@@ -73004,6 +75029,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
#endif
ins = *curr_pc++;
+ DUK_STATS_INC(thr->heap, stats_exec_opcodes);
/* Typing: use duk_small_(u)int_fast_t when decoding small
* opcode fields (op, A, B, C, BC) which fit into 16 bits
@@ -73031,7 +75057,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
duk_bool_t duk__bval; \
duk__bval = (bval); \
DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
- duk_push_boolean((duk_context *) thr, duk__bval); \
+ duk_push_boolean(thr, duk__bval); \
DUK__REPLACE_TOP_A_BREAK(); \
}
#else
@@ -73092,15 +75118,15 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
duk_int32_t val;
val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
- duk_push_int((duk_context *) thr, val);
+ duk_push_int(thr, val);
DUK__REPLACE_TOP_A_BREAK();
}
case DUK_OP_LDINTX: {
duk_int32_t val;
- val = (duk_int32_t) duk_get_int((duk_context *) thr, DUK_DEC_A(ins));
+ val = (duk_int32_t) duk_get_int(thr, DUK_DEC_A(ins));
val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */
- duk_push_int((duk_context *) thr, val);
+ duk_push_int(thr, val);
DUK__REPLACE_TOP_A_BREAK();
}
#else /* DUK_USE_EXEC_PREFER_SIZE */
@@ -73134,23 +75160,23 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
#if defined(DUK_USE_EXEC_PREFER_SIZE)
case DUK_OP_LDTHIS: {
- duk_push_this((duk_context *) thr);
+ duk_push_this(thr);
DUK__REPLACE_TOP_BC_BREAK();
}
case DUK_OP_LDUNDEF: {
- duk_to_undefined((duk_context *) thr, (duk_idx_t) DUK_DEC_BC(ins));
+ duk_to_undefined(thr, (duk_idx_t) DUK_DEC_BC(ins));
break;
}
case DUK_OP_LDNULL: {
- duk_to_null((duk_context *) thr, (duk_idx_t) DUK_DEC_BC(ins));
+ duk_to_null(thr, (duk_idx_t) DUK_DEC_BC(ins));
break;
}
case DUK_OP_LDTRUE: {
- duk_push_true((duk_context *) thr);
+ duk_push_true(thr);
DUK__REPLACE_TOP_BC_BREAK();
}
case DUK_OP_LDFALSE: {
- duk_push_false((duk_context *) thr);
+ duk_push_false(thr);
DUK__REPLACE_TOP_BC_BREAK();
}
#else /* DUK_USE_EXEC_PREFER_SIZE */
@@ -73226,8 +75252,8 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
duk_small_uint_t stridx;
stridx = duk_js_typeof_stridx(DUK__REGP_BC(ins));
- DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring_stridx((duk_context *) thr, stridx);
+ DUK_ASSERT_STRIDX_VALID(stridx);
+ duk_push_hstring_stridx(thr, stridx);
DUK__REPLACE_TOP_A_BREAK();
}
#else /* DUK_USE_EXEC_PREFER_SIZE */
@@ -73247,7 +75273,6 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
#endif /* DUK_USE_EXEC_PREFER_SIZE */
case DUK_OP_TYPEOFID: {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_t stridx;
#if !defined(DUK_USE_EXEC_PREFER_SIZE)
duk_hstring *h_str;
@@ -73267,17 +75292,17 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
act = thr->callstack_curr;
if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
/* -> [... val this] */
- tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -2);
stridx = duk_js_typeof_stridx(tv);
tv = NULL; /* no longer needed */
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
} else {
/* unresolvable, no stack changes */
stridx = DUK_STRIDX_LC_UNDEFINED;
}
DUK_ASSERT_STRIDX_VALID(stridx);
#if defined(DUK_USE_EXEC_PREFER_SIZE)
- duk_push_hstring_stridx(ctx, stridx);
+ duk_push_hstring_stridx(thr, stridx);
DUK__REPLACE_TOP_A_BREAK();
#else /* DUK_USE_EXEC_PREFER_SIZE */
h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
@@ -73844,7 +75869,6 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
case DUK_OP_POSTDECP_CR:
case DUK_OP_POSTDECP_RC:
case DUK_OP_POSTDECP_CC: {
- duk_context *ctx = (duk_context *) thr;
duk_tval *tv_obj;
duk_tval *tv_key;
duk_tval *tv_val;
@@ -73880,16 +75904,16 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
* not intuitive.
*/
- x = duk_to_number_m1(ctx);
- duk_pop(ctx);
+ x = duk_to_number_m1(thr);
+ duk_pop_unsafe(thr);
if (ins & DUK_BC_INCDECP_FLAG_DEC) {
y = x - 1.0;
} else {
y = x + 1.0;
}
- duk_push_number(ctx, y);
- tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ duk_push_number(thr, y);
+ tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(tv_val != NULL);
tv_obj = DUK__REGCONSTP_B(ins);
tv_key = DUK__REGCONSTP_C(ins);
@@ -73897,11 +75921,11 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
DUK_UNREF(rc); /* ignore */
tv_obj = NULL; /* invalidated */
tv_key = NULL; /* invalidated */
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
z = (ins & DUK_BC_INCDECP_FLAG_POST) ? x : y;
#if defined(DUK_USE_EXEC_PREFER_SIZE)
- duk_push_number(ctx, z);
+ duk_push_number(thr, z);
DUK__REPLACE_TOP_A_BREAK();
#else
tv_dst = DUK__REGP_A(ins);
@@ -73922,6 +75946,21 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
(void) duk_hobject_getprop(thr, (barg), (carg)); \
DUK__REPLACE_TOP_A_BREAK(); \
}
+#define DUK__GETPROPC_BODY(barg,carg) { \
+ /* Same as GETPROP but callability check for property-based calls. */ \
+ duk_tval *tv__targ; \
+ (void) duk_hobject_getprop(thr, (barg), (carg)); \
+ DUK_GC_TORTURE(thr->heap); \
+ tv__targ = DUK_GET_TVAL_NEGIDX(thr, -1); \
+ if (DUK_UNLIKELY(!duk_is_callable_tval(thr, tv__targ))) { \
+ /* Here we intentionally re-evaluate the macro \
+ * arguments to deal with potentially changed \
+ * valstack base pointer! \
+ */ \
+ duk_call_setup_propcall_error(thr, tv__targ, (barg), (carg)); \
+ } \
+ DUK__REPLACE_TOP_A_BREAK(); \
+ }
#define DUK__PUTPROP_BODY(aarg,barg,carg) { \
/* A -> object reg \
* B -> key reg/const \
@@ -73949,6 +75988,13 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
case DUK_OP_GETPROP_RC:
case DUK_OP_GETPROP_CC:
DUK__GETPROP_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ case DUK_OP_GETPROPC_RR:
+ case DUK_OP_GETPROPC_CR:
+ case DUK_OP_GETPROPC_RC:
+ case DUK_OP_GETPROPC_CC:
+ DUK__GETPROPC_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
+#endif
case DUK_OP_PUTPROP_RR:
case DUK_OP_PUTPROP_CR:
case DUK_OP_PUTPROP_RC:
@@ -73966,6 +76012,16 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
case DUK_OP_GETPROP_CC:
DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ case DUK_OP_GETPROPC_RR:
+ DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GETPROPC_CR:
+ DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
+ case DUK_OP_GETPROPC_RC:
+ DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
+ case DUK_OP_GETPROPC_CC:
+ DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
+#endif
case DUK_OP_PUTPROP_RR:
DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__REGP_C(ins));
case DUK_OP_PUTPROP_CR:
@@ -73986,7 +76042,6 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
case DUK_OP_DECLVAR_RC:
case DUK_OP_DECLVAR_CC: {
duk_activation *act;
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_fast_t a = DUK_DEC_A(ins);
duk_tval *tv1;
duk_hstring *name;
@@ -74010,18 +76065,18 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
if (is_func_decl) {
- duk_push_tval(ctx, DUK__REGCONSTP_C(ins));
+ duk_push_tval(thr, DUK__REGCONSTP_C(ins));
} else {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
thr->valstack_top++;
}
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
act = thr->callstack_curr;
if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
if (is_func_decl) {
/* Already declared, update value. */
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
} else {
/* Already declared but no initializer value
@@ -74030,7 +76085,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
}
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
break;
}
@@ -74047,8 +76102,8 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
* C -> escaped source
*/
- duk_push_tval((duk_context *) thr, DUK__REGCONSTP_C(ins));
- duk_push_tval((duk_context *) thr, DUK__REGCONSTP_B(ins)); /* -> [ ... escaped_source bytecode ] */
+ duk_push_tval(thr, DUK__REGCONSTP_C(ins));
+ duk_push_tval(thr, DUK__REGCONSTP_B(ins)); /* -> [ ... escaped_source bytecode ] */
duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
DUK__REPLACE_TOP_A_BREAK();
}
@@ -74067,7 +76122,6 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
* (2) that object environment record is a 'with' block.
*/
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_uint_fast_t idx;
duk_tval *tv1;
@@ -74087,8 +76141,8 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
idx = (duk_uint_fast_t) DUK_DEC_A(ins);
/* Could add direct value stack handling. */
- duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
- duk_replace(ctx, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
+ duk_replace(thr, (duk_idx_t) (idx + 1)); /* 'this' binding */
+ duk_replace(thr, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
break;
}
@@ -74138,7 +76192,6 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
}
case DUK_OP_GETVAR: {
- duk_context *ctx = (duk_context *) thr;
duk_activation *act;
duk_tval *tv1;
duk_hstring *name;
@@ -74148,8 +76201,9 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
name = DUK_TVAL_GET_STRING(tv1);
DUK_ASSERT(name != NULL);
act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
(void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
- duk_pop(ctx); /* 'this' binding is not needed here */
+ duk_pop_unsafe(thr); /* 'this' binding is not needed here */
DUK__REPLACE_TOP_A_BREAK();
}
@@ -74203,9 +76257,8 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
* for potential out-of-memory situations which will then \
* propagate out of the executor longjmp handler. \
*/ \
- ret_result = duk__handle_return(thr, \
- entry_thread, \
- entry_callstack_top); \
+ DUK_ASSERT(thr->ptr_curr_pc == NULL); \
+ ret_result = duk__handle_return(thr, entry_act); \
if (ret_result == DUK__RETHAND_RESTART) { \
goto restart_execution; \
} \
@@ -74222,13 +76275,13 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
DUK__SYNC_AND_NULL_CURR_PC();
if (op == DUK_OP_RETREG) {
- duk_push_tval((duk_context *) thr, DUK__REGP_BC(ins));
+ duk_push_tval(thr, DUK__REGP_BC(ins));
} else if (op == DUK_OP_RETUNDEF) {
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
thr->valstack_top++;
} else {
DUK_ASSERT(op == DUK_OP_RETCONST || op == DUK_OP_RETCONSTN);
- duk_push_tval((duk_context *) thr, DUK__CONSTP_BC(ins));
+ duk_push_tval(thr, DUK__CONSTP_BC(ins));
}
DUK__RETURN_SHARED();
@@ -74277,24 +76330,28 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
#endif /* DUK_USE_EXEC_PREFER_SIZE */
case DUK_OP_LABEL: {
+ duk_activation *act;
duk_catcher *cat;
duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
- /* allocate catcher and populate it (should be atomic) */
+ /* Allocate catcher and populate it (must be atomic). */
- duk_hthread_catchstack_grow(thr);
- cat = thr->catchstack + thr->catchstack_top;
- thr->catchstack_top++;
+ cat = duk_hthread_catcher_alloc(thr);
+ DUK_ASSERT(cat != NULL);
- cat->flags = DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT);
- cat->callstack_index = thr->callstack_top - 1;
+ cat->flags = (duk_uint32_t) (DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT));
cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
cat->idx_base = 0; /* unused for label */
cat->h_varname = NULL;
- DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+ cat->parent = act->cat;
+ act->cat = cat;
+
+ DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, pc_base=%ld, "
"idx_base=%ld, h_varname=%!O, label_id=%ld",
- (long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base,
+ (long) cat->flags, (long) cat->pc_base,
(long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
curr_pc += 2; /* skip jump slots */
@@ -74302,7 +76359,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
}
case DUK_OP_ENDLABEL: {
- duk_catcher *cat;
+ duk_activation *act;
#if (defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)) || defined(DUK_USE_ASSERTIONS)
duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
#endif
@@ -74310,14 +76367,12 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
#endif
- DUK_ASSERT(thr->catchstack_top >= 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_UNREF(cat);
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
- DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(cat) == bc);
+ act = thr->callstack_curr;
+ DUK_ASSERT(act->cat != NULL);
+ DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_LABEL);
+ DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(act->cat) == bc);
+ duk_hthread_catcher_unwind_nolexenv_norz(thr, act);
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
/* no need to unwind callstack */
break;
}
@@ -74340,384 +76395,34 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
/* XXX: move to helper, too large to be inline here */
case DUK_OP_TRYCATCH: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_catcher *cat;
- duk_tval *tv1;
- duk_small_uint_fast_t a;
- duk_small_uint_fast_t bc;
-
- /* A -> flags
- * BC -> reg_catch; base register for two registers used both during
- * trycatch setup and when catch is triggered
- *
- * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
- * reg_catch + 0: catch binding variable name (string).
- * Automatic declarative environment is established for
- * the duration of the 'catch' clause.
- *
- * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
- * reg_catch + 0: with 'target value', which is coerced to
- * an object and then used as a bindind object for an
- * environment record. The binding is initialized here, for
- * the 'try' clause.
- *
- * Note that a TRYCATCH generated for a 'with' statement has no
- * catch or finally parts.
- */
-
- /* XXX: TRYCATCH handling should be reworked to avoid creating
- * an explicit scope unless it is actually needed (e.g. function
- * instances or eval is executed inside the catch block). This
- * rework is not trivial because the compiler doesn't have an
- * intermediate representation. When the rework is done, the
- * opcode format can also be made more straightforward.
- */
-
- /* XXX: side effect handling is quite awkward here */
-
- DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
- "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
- (long) DUK_DEC_BC(ins),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
- (unsigned long) DUK_DEC_A(ins)));
-
- a = DUK_DEC_A(ins);
- bc = DUK_DEC_BC(ins);
-
- /* Registers 'bc' and 'bc + 1' are written in longjmp handling
- * and if their previous values (which are temporaries) become
- * unreachable -and- have a finalizer, there'll be a function
- * call during error handling which is not supported now (GH-287).
- * Ensure that both 'bc' and 'bc + 1' have primitive values to
- * guarantee no finalizer calls in error handling. Scrubbing also
- * ensures finalizers for the previous values run here rather than
- * later. Error handling related values are also written to 'bc'
- * and 'bc + 1' but those values never become unreachable during
- * error handling, so there's no side effect problem even if the
- * error value has a finalizer.
- */
- duk_dup(ctx, bc); /* Stabilize value. */
- duk_to_undefined(ctx, bc);
- duk_to_undefined(ctx, bc + 1);
-
- /* Ensure a catchstack entry is available. One entry
- * is guaranteed even if side effects cause function
- * calls and the catchstack is shrunk because some
- * spare room is left behind by a shrink operation.
- */
- duk_hthread_catchstack_grow(thr);
-
- /* Allocate catcher and populate it. Doesn't have to
- * be fully atomic, but the catcher must be in a
- * consistent state if side effects (such as finalizer
- * calls) occur.
- */
-
- DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size);
- cat = thr->catchstack + thr->catchstack_top;
- thr->catchstack_top++;
-
- cat->flags = DUK_CAT_TYPE_TCF;
- cat->h_varname = NULL;
- cat->callstack_index = thr->callstack_top - 1;
- cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
- cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
-
- if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
- cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
- }
- if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
- cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
- }
- if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
- DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
- cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
- tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
-
- /* borrowed reference; although 'tv1' comes from a register,
- * its value was loaded using LDCONST so the constant will
- * also exist and be reachable.
- */
- cat->h_varname = DUK_TVAL_GET_STRING(tv1);
- } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
- duk_hobjenv *env;
- duk_hobject *target;
-
- /* Delayed env initialization for activation (if needed). */
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack_curr;
- DUK_ASSERT(act != NULL);
- if (act->lex_env == NULL) {
- DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
- DUK_ASSERT(act->var_env == NULL);
-
- duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack_curr; /* relookup, side effects */
- DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
- }
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
-
- /* Coerce 'with' target. */
- target = duk_to_hobject(ctx, -1);
- DUK_ASSERT(target != NULL);
-
- /* Create an object environment; it is not pushed
- * so avoid side effects very carefully until it is
- * referenced.
- */
- env = duk_hobjenv_alloc(thr,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
- DUK_ASSERT(env != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
- env->target = target; /* always provideThis=true */
- DUK_HOBJECT_INCREF(thr, target);
- env->has_this = 1;
- DUK_ASSERT_HOBJENV_VALID(env);
- DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env));
-
- act = thr->callstack_curr; /* relookup (side effects) */
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
- DUK_ASSERT(act->lex_env != NULL);
- DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env);
- act->lex_env = (duk_hobject *) env; /* Now reachable. */
- DUK_HOBJECT_INCREF(thr, (duk_hobject *) env);
- /* Net refcount change to act->lex_env is 0: incref for env's
- * prototype, decref for act->lex_env overwrite.
- */
-
- /* Set catcher lex_env active (affects unwind)
- * only when the whole setup is complete.
- */
- cat = thr->catchstack + thr->catchstack_top - 1;
- cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
- } else {
- ;
- }
-
- DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
- "idx_base=%ld, h_varname=%!O",
- (unsigned long) cat->flags, (long) cat->callstack_index,
- (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
-
- duk_pop(ctx);
-
+ duk__handle_op_trycatch(thr, ins, curr_pc);
curr_pc += 2; /* skip jump slots */
break;
}
case DUK_OP_ENDTRY: {
- duk_catcher *cat;
- duk_tval *tv1;
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
-
- DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
- DUK_CAT_CLEAR_CATCH_ENABLED(cat);
-
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- tv1 = NULL;
-
- tv1 = thr->valstack + cat->idx_base + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
- tv1 = NULL;
-
- DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
- } else {
- DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- }
-
- curr_pc = cat->pc_base + 1;
+ curr_pc = duk__handle_op_endtry(thr, ins);
break;
}
case DUK_OP_ENDCATCH: {
- duk_activation *act;
- duk_catcher *cat;
- duk_tval *tv1;
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
-
- act = thr->callstack_curr;
- DUK_ASSERT(act != NULL);
-
- if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
- duk_hobject *prev_env;
-
- /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
- DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
- DUK_ASSERT(act->lex_env != NULL);
-
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
-
- prev_env = act->lex_env;
- DUK_ASSERT(prev_env != NULL);
- act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
- DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
- DUK_HOBJECT_INCREF(thr, act->lex_env);
- DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
- }
-
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- tv1 = NULL;
-
- tv1 = thr->valstack + cat->idx_base + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
- tv1 = NULL;
-
- DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
- } else {
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- }
-
- curr_pc = cat->pc_base + 1;
+ duk__handle_op_endcatch(thr, ins);
break;
}
case DUK_OP_ENDFIN: {
- duk_context *ctx = (duk_context *) thr;
- duk_catcher *cat;
- duk_tval *tv1;
- duk_small_uint_t cont_type;
- duk_small_uint_t ret_result;
-
/* Sync and NULL early. */
DUK__SYNC_AND_NULL_CURR_PC();
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
-
- /* CATCH flag may be enabled or disabled here; it may be enabled if
- * the statement has a catch block but the try block does not throw
- * an error.
- */
- DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
- /* XXX: assert idx_base */
-
- DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
- (duk_tval *) (thr->valstack + cat->idx_base + 0),
- (duk_tval *) (thr->valstack + cat->idx_base + 1)));
-
- tv1 = thr->valstack + cat->idx_base + 1; /* type */
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
-
- switch (cont_type) {
- case DUK_LJ_TYPE_NORMAL: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
- "dismantle catcher, resume execution after ENDFIN"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- goto restart_execution;
- }
- case DUK_LJ_TYPE_RETURN: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
- "catcher, handle return, lj.value1=%!T", thr->valstack + cat->idx_base));
-
- /* Not necessary to unwind catchstack: return handling will
- * do it. The finally flag of 'cat' is no longer set. The
- * catch flag may be set, but it's not checked by return handling.
- */
- DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
-#if 0
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
-#endif
-
- duk_push_tval(ctx, thr->valstack + cat->idx_base);
- ret_result = duk__handle_return(thr,
- entry_thread,
- entry_callstack_top);
- if (ret_result == DUK__RETHAND_RESTART) {
- goto restart_execution;
- }
- DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
-
- DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
+ if (duk__handle_op_endfin(thr, ins, entry_act) != 0) {
return;
}
- case DUK_LJ_TYPE_BREAK:
- case DUK_LJ_TYPE_CONTINUE: {
- duk_uint_t label_id;
- duk_small_uint_t lj_type;
- /* Not necessary to unwind catchstack: break/continue
- * handling will do it. The finally flag of 'cat' is
- * no longer set. The catch flag may be set, but it's
- * not checked by break/continue handling.
- */
-#if 0
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
-#endif
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
-#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
- label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
-#else
- label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
-#endif
- lj_type = cont_type;
- duk__handle_break_or_continue(thr, label_id, lj_type);
- goto restart_execution;
- }
- default: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
- "dismantle catcher, re-throw error",
- (long) cont_type));
-
- duk_push_tval(ctx, thr->valstack + cat->idx_base);
-
- duk_err_setup_ljstate1(thr, (duk_small_int_t) cont_type, thr->valstack + cat->idx_base);
- /* No debugger Throw notify check on purpose (rethrow). */
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- }
- }
-
- /* Must restart in all cases because we NULLed thr->ptr_curr_pc. */
- DUK_UNREACHABLE();
- break;
+ /* Must restart because we NULLed out curr_pc. */
+ goto restart_execution;
}
case DUK_OP_THROW: {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
/* Note: errors are augmented when they are created, not
@@ -74731,16 +76436,16 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
*/
DUK__SYNC_AND_NULL_CURR_PC();
- duk_dup(ctx, (duk_idx_t) bc);
+ duk_dup(thr, (duk_idx_t) bc);
DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
duk_err_augment_error_throw(thr);
DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
#endif
- duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(ctx, -1));
+ duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
#if defined(DUK_USE_DEBUGGER_SUPPORT)
duk_err_check_debugger_integration(thr);
#endif
@@ -74766,9 +76471,9 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
*/
#if defined(DUK_USE_PREFER_SIZE)
- duk_dup((duk_context *) thr, a);
- duk_replace((duk_context *) thr, bc);
- duk_to_undefined((duk_context *) thr, bc + 1);
+ duk_dup(thr, (duk_idx_t) a);
+ duk_replace(thr, (duk_idx_t) bc);
+ duk_to_undefined(thr, (duk_idx_t) (bc + 1));
#else
duk_tval *tv1;
duk_tval *tv2;
@@ -74790,129 +76495,48 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
break;
}
- case DUK_OP_EVALCALL: {
- /* Eval call or a normal call made using the identifier 'eval'.
- * Eval calls are never handled as tail calls for simplicity.
- */
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t nargs;
- duk_uint_fast_t idx;
- duk_idx_t num_stack_args;
- duk_small_uint_t call_flags;
- duk_tval *tv_func;
- duk_hobject *obj_func;
-#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- duk_hcompfunc *fun;
-#endif
-
- /* Technically we should also check for the possibility of
- * a pure Ecmascript-to-Ecmascript call: while built-in eval()
- * is native, it's possible for the 'eval' identifier to be
- * shadowed. In practice that would be rare and optimizing the
- * C call stack for that case is a bit pointless.
- */
- nargs = (duk_small_uint_fast_t) DUK_DEC_A(ins);
- idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
- duk_set_top(ctx, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */
-
- call_flags = 0;
- tv_func = DUK_GET_TVAL_POSIDX(ctx, idx);
- if (DUK_TVAL_IS_OBJECT(tv_func)) {
- obj_func = DUK_TVAL_GET_OBJECT(tv_func);
- DUK_ASSERT(obj_func != NULL);
- if (DUK_HOBJECT_IS_NATFUNC(obj_func) &&
- ((duk_hnatfunc *) obj_func)->func == duk_bi_global_object_eval) {
- DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was 'eval' -> direct eval"));
- call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
- }
- }
- num_stack_args = nargs;
- duk_handle_call_unprotected(thr, num_stack_args, call_flags);
-
-#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- fun = DUK__FUN();
-#endif
- duk_set_top(ctx, (duk_idx_t) fun->nregs);
- break;
- }
-
- case DUK_OP_CALL:
- case DUK_OP_TAILCALL: {
- /* DUK_OP_CALL: plain call, not tailcall compatible.
- *
- * DUK_OP_TAILCALL: plain call which is tailcall
- * compatible. Tail call may not be possible due
- * to e.g. target not being an Ecmascript function.
- *
- * Not a direct eval call. Indirect eval calls don't
- * need special handling here.
- */
+ /* XXX: in some cases it's faster NOT to reuse the value
+ * stack but rather copy the arguments on top of the stack
+ * (mainly when the calling value stack is large and the value
+ * stack resize would be large).
+ */
- /* To determine whether to use an optimized Ecmascript-to-Ecmascript
- * call, we need to know whether the final, non-bound function is an
- * Ecmascript function. Current implementation is to first try an
- * Ecma-to-Ecma call setup which also resolves the bound function
- * chain. The setup attempt overwrites call target at DUK__REGP(idx)
- * and may also fudge the argument list. However, it won't resolve
- * the effective 'this' binding if the setup fails. This is somewhat
- * awkward, and the two call setup code paths should be merged.
+ case DUK_OP_CALL0:
+ case DUK_OP_CALL1:
+ case DUK_OP_CALL2:
+ case DUK_OP_CALL3:
+ case DUK_OP_CALL4:
+ case DUK_OP_CALL5:
+ case DUK_OP_CALL6:
+ case DUK_OP_CALL7: {
+ /* Opcode packs 4 flag bits: 1 for indirect, 3 map
+ * 1:1 to three lowest call handling flags.
*
- * If an Ecma-to-Ecma call is not possible, the actual call handling
- * will do another (unnecessary) attempt to resolve the bound function.
+ * A -> nargs or register with nargs (indirect)
+ * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
*/
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t nargs;
- duk_uint_fast_t idx;
- duk_idx_t num_stack_args;
+ duk_idx_t nargs;
+ duk_idx_t idx;
duk_small_uint_t call_flags;
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
duk_hcompfunc *fun;
#endif
- /* A -> nargs
- * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
- */
-
- /* XXX: in some cases it's faster NOT to reuse the value
- * stack but rather copy the arguments on top of the stack
- * (mainly when the calling value stack is large and the value
- * stack resize would be large). See DUK_OP_NEW.
- */
+ DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
+ DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) == 0);
- nargs = (duk_small_uint_fast_t) DUK_DEC_A(ins);
- idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
- duk_set_top(ctx, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */
+ nargs = (duk_idx_t) DUK_DEC_A(ins);
+ call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
+ idx = (duk_idx_t) DUK_DEC_BC(ins);
- /* DUK_OP_CALL and DUK_OP_TAILCALL are consecutive
- * which allows a simple bit test.
- */
- DUK_ASSERT((DUK_OP_CALL & 0x01) == 0);
- DUK_ASSERT((DUK_OP_TAILCALL & 0x01) == 1);
- call_flags = (ins & (1UL << DUK_BC_SHIFT_OP)) ? DUK_CALL_FLAG_IS_TAILCALL : 0;
-
- num_stack_args = nargs;
- if (duk_handle_ecma_call_setup(thr, num_stack_args, call_flags)) {
- /* Ecma-to-ecma call possible, may or may not be a tail call.
- * Avoid C recursion by being clever.
- */
- DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
- /* curr_pc synced by duk_handle_ecma_call_setup() */
+ if (duk__executor_handle_call(thr, idx, nargs, call_flags)) {
+ /* curr_pc synced by duk_handle_call_unprotected() */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
goto restart_execution;
}
-
- /* Recompute argument count: bound function handling may have shifted. */
- num_stack_args = duk_get_top(ctx) - (idx + 2);
- DUK_DDD(DUK_DDDPRINT("recomputed arg count: %ld\n", (long) num_stack_args));
-
- /* Target is either a lightfunc or a function object.
- * We don't need to check for eval handling here: the
- * call may be an indirect eval ('myEval("something")')
- * but that requires no special handling.
- */
-
- duk_handle_call_unprotected(thr, num_stack_args, 0 /*call_flags*/);
+ DUK_ASSERT(thr->ptr_curr_pc != NULL);
/* duk_js_call.c is required to restore the stack reserve
* so we only need to reset the top.
@@ -74920,97 +76544,103 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
fun = DUK__FUN();
#endif
- duk_set_top(ctx, (duk_idx_t) fun->nregs);
+ duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
/* No need to reinit setjmp() catchpoint, as call handling
* will store and restore our state.
- */
-
- /* When debugger is enabled, we need to recheck the activation
+ *
+ * When debugger is enabled, we need to recheck the activation
* status after returning. This is now handled by call handling
* and heap->dbg_force_restart.
*/
break;
}
- case DUK_OP_NEW: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
-#if defined(DUK_USE_EXEC_PREFER_SIZE)
+ case DUK_OP_CALL8:
+ case DUK_OP_CALL9:
+ case DUK_OP_CALL10:
+ case DUK_OP_CALL11:
+ case DUK_OP_CALL12:
+ case DUK_OP_CALL13:
+ case DUK_OP_CALL14:
+ case DUK_OP_CALL15: {
+ /* Indirect variant. */
+ duk_uint_fast_t nargs;
+ duk_idx_t idx;
+ duk_small_uint_t call_flags;
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
duk_hcompfunc *fun;
#endif
-#else
- duk_small_uint_fast_t count;
- duk_tval *tv_src;
-#endif
-
- /* A -> num args (N)
- * BC -> target register and start reg: constructor, arg1, ..., argN
- */
- /* duk_new() will call the constuctor using duk_handle_call().
- * A constructor call prevents a yield from inside the constructor,
- * even if the constructor is an Ecmascript function.
- */
+ DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
+ DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) != 0);
- /* Don't need to sync curr_pc here; duk_new() will do that
- * when it augments the created error.
- */
-
-#if defined(DUK_USE_EXEC_PREFER_SIZE)
- /* This alternative relies on our being allowed to trash anything
- * above 'bc' so we can just reuse the argument registers which
- * means smaller value stack use. Footprint is a bit smaller.
- */
- duk_set_top(ctx, (duk_idx_t) (bc + a + 1));
- duk_new(ctx, (duk_idx_t) a); /* [... constructor arg1 ... argN] -> [retval] */
+ nargs = (duk_uint_fast_t) DUK_DEC_A(ins);
+ DUK__LOOKUP_INDIRECT(nargs);
+ call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
+ idx = (duk_idx_t) DUK_DEC_BC(ins);
- /* The return value is already in its correct place at the stack,
- * i.e. it has replaced the 'constructor' at index bc. Just reset
- * top and we're done.
- */
+ if (duk__executor_handle_call(thr, idx, (duk_idx_t) nargs, call_flags)) {
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ goto restart_execution;
+ }
+ DUK_ASSERT(thr->ptr_curr_pc != NULL);
#if !defined(DUK_USE_EXEC_FUN_LOCAL)
fun = DUK__FUN();
#endif
- duk_set_top(ctx, (duk_idx_t) fun->nregs);
-#else /* DUK_USE_EXEC_PREFER_SIZE */
- /* Faster alternative is to duplicate the values to avoid a resize.
- * This depends on the relative size between the value stack and
- * the argument count, though.
- */
- count = a + 1;
- duk_require_stack(ctx, count);
- tv_src = DUK_GET_TVAL_POSIDX(ctx, bc);
- duk__push_tvals_incref_only(thr, tv_src, count);
- duk_new(ctx, (duk_idx_t) a); /* [... constructor arg1 ... argN] -> [retval] */
- duk_replace(ctx, bc);
-#endif /* DUK_USE_EXEC_PREFER_SIZE */
-
- /* When debugger is enabled, we need to recheck the activation
- * status after returning. This is now handled by call handling
- * and heap->dbg_force_restart.
- */
+ duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
break;
}
case DUK_OP_NEWOBJ: {
- duk_context *ctx = (duk_context *) thr;
- duk_push_object(ctx);
+ duk_push_object(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_hobject *h;
+ h = duk_require_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
+ }
+#endif
+#if !defined(DUK_USE_PREFER_SIZE)
+ /* XXX: could do a direct props realloc, but need hash size */
+ duk_hobject_resize_entrypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
+#endif
DUK__REPLACE_TOP_BC_BREAK();
}
case DUK_OP_NEWARR: {
- duk_context *ctx = (duk_context *) thr;
- duk_push_array(ctx);
+ duk_push_array(thr);
+#if defined(DUK_USE_ASSERTIONS)
+ {
+ duk_hobject *h;
+ h = duk_require_hobject(thr, -1);
+ DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
+ DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(h));
+ }
+#endif
+#if !defined(DUK_USE_PREFER_SIZE)
+ duk_hobject_realloc_props(thr,
+ duk_known_hobject(thr, -1),
+ 0 /*new_e_size*/,
+ DUK_DEC_A(ins) /*new_a_size*/,
+ 0 /*new_h_size*/,
+ 0 /*abandon_array*/);
+#if 0
+ duk_hobject_resize_arraypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
+#endif
+#endif
DUK__REPLACE_TOP_BC_BREAK();
}
case DUK_OP_MPUTOBJ:
case DUK_OP_MPUTOBJI: {
- duk_context *ctx = (duk_context *) thr;
duk_idx_t obj_idx;
duk_uint_fast_t idx, idx_end;
duk_small_uint_fast_t count;
@@ -75023,11 +76653,11 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
*/
obj_idx = DUK_DEC_A(ins);
- DUK_ASSERT(duk_is_object(ctx, obj_idx));
+ DUK_ASSERT(duk_is_object(thr, obj_idx));
idx = (duk_uint_fast_t) DUK_DEC_B(ins);
if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
- DUK__LOOKUP_INDIRECT_INDEX(idx);
+ DUK__LOOKUP_INDIRECT(idx);
}
count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
@@ -75035,7 +76665,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
idx_end = idx + count;
#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(ctx))) {
+ if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(thr))) {
/* XXX: use duk_is_valid_index() instead? */
/* XXX: improve check; check against nregs, not against top */
DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
@@ -75053,9 +76683,9 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
*/
do {
/* XXX: faster initialization (direct access or better primitives) */
- duk_dup(ctx, idx);
- duk_dup(ctx, idx + 1);
- duk_def_prop(ctx, obj_idx, DUK_DEFPROP_HAVE_VALUE |
+ duk_dup(thr, (duk_idx_t) idx);
+ duk_dup(thr, (duk_idx_t) (idx + 1));
+ duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_FORCE |
DUK_DEFPROP_SET_WRITABLE |
DUK_DEFPROP_SET_ENUMERABLE |
@@ -75067,43 +76697,12 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
case DUK_OP_INITSET:
case DUK_OP_INITGET: {
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t is_set = (op == DUK_OP_INITSET);
- duk_uint_fast_t idx;
- duk_uint_t defprop_flags;
-
- /* A -> object register (acts as a source)
- * BC -> BC+0 contains key, BC+1 closure (value)
- */
-
- /* INITSET/INITGET are only used to initialize object literal keys.
- * There may be a previous propery in ES2015 because duplicate property
- * names are allowed.
- */
-
- /* This could be made more optimal by accessing internals directly. */
-
- idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
- duk_dup(ctx, (duk_idx_t) (idx + 0)); /* key */
- duk_dup(ctx, (duk_idx_t) (idx + 1)); /* getter/setter */
- if (is_set) {
- defprop_flags = DUK_DEFPROP_HAVE_SETTER |
- DUK_DEFPROP_FORCE |
- DUK_DEFPROP_SET_ENUMERABLE |
- DUK_DEFPROP_SET_CONFIGURABLE;
- } else {
- defprop_flags = DUK_DEFPROP_HAVE_GETTER |
- DUK_DEFPROP_FORCE |
- DUK_DEFPROP_SET_ENUMERABLE |
- DUK_DEFPROP_SET_CONFIGURABLE;
- }
- duk_def_prop(ctx, (duk_idx_t) DUK_DEC_A(ins), defprop_flags);
+ duk__handle_op_initset_initget(thr, ins);
break;
}
case DUK_OP_MPUTARR:
case DUK_OP_MPUTARRI: {
- duk_context *ctx = (duk_context *) thr;
duk_idx_t obj_idx;
duk_uint_fast_t idx, idx_end;
duk_small_uint_fast_t count;
@@ -75117,11 +76716,11 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
*/
obj_idx = DUK_DEC_A(ins);
- DUK_ASSERT(duk_is_object(ctx, obj_idx));
+ DUK_ASSERT(duk_is_object(thr, obj_idx));
idx = (duk_uint_fast_t) DUK_DEC_B(ins);
if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
- DUK__LOOKUP_INDIRECT_INDEX(idx);
+ DUK__LOOKUP_INDIRECT(idx);
}
count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
@@ -75129,7 +76728,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
idx_end = idx + count;
#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx_end > (duk_uint_fast_t) duk_get_top(ctx)) {
+ if (idx_end > (duk_uint_fast_t) duk_get_top(thr)) {
/* XXX: use duk_is_valid_index() instead? */
/* XXX: improve check; check against nregs, not against top */
DUK__INTERNAL_ERROR("MPUTARR out of bounds");
@@ -75159,8 +76758,8 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
* and finally set 'length' manually in the end (as already happens now).
*/
- duk_dup(ctx, idx);
- duk_xdef_prop_index_wec(ctx, obj_idx, arr_idx);
+ duk_dup(thr, (duk_idx_t) idx);
+ duk_xdef_prop_index_wec(thr, obj_idx, arr_idx);
idx++;
arr_idx++;
@@ -75197,73 +76796,12 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
}
case DUK_OP_INITENUM: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
-
- /*
- * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
- * If called with 'null' or 'undefined', this opcode returns 'null' as
- * the enumerator, which is special cased in NEXTENUM. This simplifies
- * the compiler part
- */
-
- /* B -> register for writing enumerator object
- * C -> value to be enumerated (register)
- */
-
- if (duk_is_null_or_undefined(ctx, (duk_idx_t) c)) {
- duk_push_null(ctx);
- duk_replace(ctx, (duk_idx_t) b);
- } else {
- duk_dup(ctx, (duk_idx_t) c);
- duk_to_object(ctx, -1);
- duk_hobject_enumerator_create(ctx, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
- duk_replace(ctx, (duk_idx_t) b);
- }
+ duk__handle_op_initenum(thr, ins);
break;
}
case DUK_OP_NEXTENUM: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
-
- /*
- * NEXTENUM checks whether the enumerator still has unenumerated
- * keys. If so, the next key is loaded to the target register
- * and the next instruction is skipped. Otherwise the next instruction
- * will be executed, jumping out of the enumeration loop.
- */
-
- /* B -> target register for next key
- * C -> enum register
- */
-
- DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b),
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) c)));
-
- if (duk_is_object(ctx, (duk_idx_t) c)) {
- /* XXX: assert 'c' is an enumerator */
- duk_dup(ctx, (duk_idx_t) c);
- if (duk_hobject_enumerator_next(ctx, 0 /*get_value*/)) {
- /* [ ... enum ] -> [ ... next_key ] */
- DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
- (duk_tval *) duk_get_tval(ctx, -1)));
- curr_pc++;
- } else {
- /* [ ... enum ] -> [ ... ] */
- DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
- thr->valstack_top++;
- }
- duk_replace(ctx, (duk_idx_t) b);
- } else {
- /* 'null' enumerator case -> behave as with an empty enumerator */
- DUK_ASSERT(duk_is_null(ctx, (duk_idx_t) c));
- DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
- }
+ curr_pc += duk__handle_op_nextenum(thr, ins);
break;
}
@@ -75296,7 +76834,9 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
}
case DUK_OP_NOP: {
- /* nop */
+ /* Nop, ignored, but ABC fields may carry a value e.g.
+ * for indirect opcode handling.
+ */
break;
}
@@ -75305,6 +76845,46 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
break;
}
+#if defined(DUK_USE_ES6)
+ case DUK_OP_NEWTARGET: {
+ /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation
+ * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget
+ *
+ * No newTarget support now, so as a first approximation
+ * use the resolved (non-bound) target function.
+ */
+ /* XXX: C API: push_new_target()? */
+ duk_activation *act;
+
+ act = thr->callstack_curr;
+ DUK_ASSERT(act != NULL);
+
+ /* Check CONSTRUCT flag from current function, or if running
+ * direct eval, from a non-direct-eval parent (with possibly
+ * more than one nested direct eval). An alternative to this
+ * would be to store [[NewTarget]] as a hidden symbol of the
+ * lexical scope, and then just look up that variable.
+ */
+ for (;;) {
+ if (act == NULL) {
+ duk_push_undefined(thr);
+ break;
+ }
+ if (act->flags & DUK_ACT_FLAG_CONSTRUCT) {
+ duk_push_tval(thr, &act->tv_func);
+ break;
+ } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+ act = act->parent;
+ } else {
+ duk_push_undefined(thr);
+ break;
+ }
+ }
+
+ DUK__REPLACE_TOP_BC_BREAK();
+ }
+#endif /* DUK_USE_ES6 */
+
#if !defined(DUK_USE_EXEC_PREFER_SIZE)
#if !defined(DUK_USE_ES7_EXP_OPERATOR)
case DUK_OP_EXP_RR:
@@ -75312,24 +76892,16 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
case DUK_OP_EXP_RC:
case DUK_OP_EXP_CC:
#endif
- case DUK_OP_UNUSED194:
- case DUK_OP_UNUSED195:
- case DUK_OP_UNUSED196:
- case DUK_OP_UNUSED197:
- case DUK_OP_UNUSED198:
- case DUK_OP_UNUSED199:
- case DUK_OP_UNUSED200:
- case DUK_OP_UNUSED201:
- case DUK_OP_UNUSED202:
- case DUK_OP_UNUSED203:
- case DUK_OP_UNUSED204:
- case DUK_OP_UNUSED205:
- case DUK_OP_UNUSED206:
+#if !defined(DUK_USE_ES6)
+ case DUK_OP_NEWTARGET:
+#endif
+#if !defined(DUK_USE_VERBOSE_ERRORS)
+ case DUK_OP_GETPROPC_RR:
+ case DUK_OP_GETPROPC_CR:
+ case DUK_OP_GETPROPC_RC:
+ case DUK_OP_GETPROPC_CC:
+#endif
case DUK_OP_UNUSED207:
- case DUK_OP_UNUSED208:
- case DUK_OP_UNUSED209:
- case DUK_OP_UNUSED210:
- case DUK_OP_UNUSED211:
case DUK_OP_UNUSED212:
case DUK_OP_UNUSED213:
case DUK_OP_UNUSED214:
@@ -75381,7 +76953,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
* a small detail and obviously compiler dependent.
*/
/* default: clause omitted on purpose */
-#else
+#else /* DUK_USE_EXEC_PREFER_SIZE */
default:
#endif /* DUK_USE_EXEC_PREFER_SIZE */
{
@@ -75433,6 +77005,7 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
#undef DUK__DELPROP_BODY
#undef DUK__EQ_BODY
#undef DUK__FUN
+#undef DUK__GETPROPC_BODY
#undef DUK__GETPROP_BODY
#undef DUK__GE_BODY
#undef DUK__GT_BODY
@@ -75445,13 +77018,14 @@ DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *
#undef DUK__LE_BODY
#undef DUK__LONGJMP_RESTART
#undef DUK__LONGJMP_RETHROW
-#undef DUK__LOOKUP_INDIRECT_INDEX
+#undef DUK__LOOKUP_INDIRECT
#undef DUK__LT_BODY
#undef DUK__MASK_A
#undef DUK__MASK_B
#undef DUK__MASK_BC
#undef DUK__MASK_C
#undef DUK__NEQ_BODY
+#undef DUK__NOINLINE_PERF
#undef DUK__PUTPROP_BODY
#undef DUK__RCBIT_B
#undef DUK__RCBIT_C
@@ -75633,11 +77207,10 @@ DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
/* E5 Section 9.3.1 */
DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_small_uint_t s2n_flags;
duk_double_t d;
- DUK_ASSERT(duk_is_string(ctx, -1));
+ DUK_ASSERT(duk_is_string(thr, -1));
/* Quite lenient, e.g. allow empty as zero, but don't allow trailing
* garbage.
@@ -75656,11 +77229,11 @@ DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT |
DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT;
- duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
+ duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
#if defined(DUK_USE_PREFER_SIZE)
- d = duk_get_number(ctx, -1);
- duk_pop(ctx);
+ d = duk_get_number(thr, -1);
+ duk_pop_unsafe(thr);
#else
thr->valstack_top--;
DUK_ASSERT(DUK_TVAL_IS_NUMBER(thr->valstack_top));
@@ -75674,8 +77247,6 @@ DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
}
DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
- duk_context *ctx = (duk_hthread *) thr;
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv != NULL);
@@ -75703,22 +77274,22 @@ DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL);
}
- duk_push_hstring(ctx, h);
+ duk_push_hstring(thr, h);
return duk__tonumber_string_raw(thr);
}
case DUK_TAG_BUFFER: /* plain buffer treated like object */
case DUK_TAG_OBJECT: {
duk_double_t d;
- duk_push_tval(ctx, tv);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
+ duk_push_tval(thr, tv);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
/* recursive call for a primitive value (guaranteed not to cause second
* recursion).
*/
- DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
- d = duk_js_tonumber(thr, duk_get_tval(ctx, -1));
+ DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
+ d = duk_js_tonumber(thr, duk_get_tval(thr, -1));
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
return d;
}
case DUK_TAG_POINTER: {
@@ -75768,7 +77339,7 @@ DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
/* NaN and Infinity have the same exponent so it's a cheap
* initial check for the rare path.
*/
- if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x))) {
+ if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x) != 0U)) {
if (duk_double_is_nan(x)) {
return 0.0;
} else {
@@ -76003,8 +77574,7 @@ DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
#endif /* DUK_USE_PARANOID_MATH */
}
-DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
duk_uint_t type_mask_x;
duk_uint_t type_mask_y;
@@ -76127,7 +77697,7 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
if (!DUK_TVAL_STRING_IS_SYMBOL(tv_y)) {
duk_double_t d1, d2;
d1 = DUK_TVAL_GET_NUMBER(tv_x);
- d2 = duk_to_number_tval(ctx, tv_y);
+ d2 = duk_to_number_tval(thr, tv_y);
return duk__js_equals_number(d1, d2);
}
}
@@ -76135,7 +77705,7 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
if (!DUK_TVAL_STRING_IS_SYMBOL(tv_x)) {
duk_double_t d1, d2;
d1 = DUK_TVAL_GET_NUMBER(tv_y);
- d2 = duk_to_number_tval(ctx, tv_x);
+ d2 = duk_to_number_tval(thr, tv_x);
return duk__js_equals_number(d1, d2);
}
}
@@ -76149,14 +77719,14 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
*/
if (type_mask_x & DUK_TYPE_MASK_BOOLEAN) {
DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1);
- duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_x));
- duk_push_tval(ctx, tv_y);
+ duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_x));
+ duk_push_tval(thr, tv_y);
goto recursive_call;
}
if (type_mask_y & DUK_TYPE_MASK_BOOLEAN) {
DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
- duk_push_tval(ctx, tv_x);
- duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
+ duk_push_tval(thr, tv_x);
+ duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_y));
goto recursive_call;
}
@@ -76164,17 +77734,17 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
if ((type_mask_x & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER)) &&
(type_mask_y & DUK_TYPE_MASK_OBJECT)) {
/* No symbol check needed because symbols and strings are accepted. */
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_to_primitive(ctx, -1, DUK_HINT_NONE); /* apparently no hint? */
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_to_primitive(thr, -1, DUK_HINT_NONE); /* apparently no hint? */
goto recursive_call;
}
if ((type_mask_x & DUK_TYPE_MASK_OBJECT) &&
(type_mask_y & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER))) {
/* No symbol check needed because symbols and strings are accepted. */
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* apparently no hint? */
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_to_primitive(thr, -2, DUK_HINT_NONE); /* apparently no hint? */
goto recursive_call;
}
@@ -76186,10 +77756,10 @@ DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, d
{
duk_bool_t rc;
rc = duk_js_equals_helper(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1),
+ DUK_GET_TVAL_NEGIDX(thr, -2),
+ DUK_GET_TVAL_NEGIDX(thr, -1),
0 /*flags:nonstrict*/);
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
return rc;
}
}
@@ -76381,8 +77951,7 @@ DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk
}
#endif /* DUK_USE_PARANOID_MATH */
-DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
duk_double_t d1, d2;
duk_small_int_t rc;
duk_bool_t retval;
@@ -76411,20 +77980,20 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x,
/* Slow path */
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
- duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
} else {
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
+ duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
}
/* Note: reuse variables */
- tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
- tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
+ tv_x = DUK_GET_TVAL_NEGIDX(thr, -2);
+ tv_y = DUK_GET_TVAL_NEGIDX(thr, -1);
if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
@@ -76434,7 +78003,7 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x,
if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) {
rc = duk_js_string_compare(h1, h2);
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
if (rc < 0) {
return retval ^ 1;
} else {
@@ -76450,27 +78019,27 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x,
/* Ordering should not matter (E5 Section 11.8.5, step 3.a). */
#if 0
if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
- d1 = duk_to_number_m2(ctx);
- d2 = duk_to_number_m1(ctx);
+ d1 = duk_to_number_m2(thr);
+ d2 = duk_to_number_m1(thr);
} else {
- d2 = duk_to_number_m1(ctx);
- d1 = duk_to_number_m2(ctx);
+ d2 = duk_to_number_m1(thr);
+ d1 = duk_to_number_m2(thr);
}
#endif
- d1 = duk_to_number_m2(ctx);
- d2 = duk_to_number_m1(ctx);
+ d1 = duk_to_number_m2(thr);
+ d2 = duk_to_number_m1(thr);
- /* We want to duk_pop_2(ctx); because the values are numbers
+ /* We want to duk_pop_2_unsafe(thr); because the values are numbers
* no decref check is needed.
*/
#if defined(DUK_USE_PREFER_SIZE)
- duk_pop_2(ctx);
+ duk_pop_2_nodecref_unsafe(thr);
#else
- DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(ctx, -2)));
- DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(ctx, -1)));
- DUK_ASSERT(duk_get_top(ctx) >= 2);
- ((duk_hthread *) ctx)->valstack_top -= 2;
- tv_x = ((duk_hthread *) ctx)->valstack_top;
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -2)));
+ DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -1)));
+ DUK_ASSERT(duk_get_top(thr) >= 2);
+ thr->valstack_top -= 2;
+ tv_x = thr->valstack_top;
tv_y = tv_x + 1;
DUK_TVAL_SET_UNDEFINED(tv_x); /* Value stack policy */
DUK_TVAL_SET_UNDEFINED(tv_y);
@@ -76500,13 +78069,12 @@ DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x,
*/
DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *func;
duk_hobject *val;
duk_hobject *proto;
duk_tval *tv;
- duk_uint_t sanity;
duk_bool_t skip_first;
+ duk_uint_t sanity;
/*
* Get the values onto the stack first. It would be possible to cover
@@ -76518,52 +78086,41 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
* Using duk_require_hobject() is thus correct (except for error msg).
*/
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- func = duk_require_hobject(ctx, -1);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ func = duk_require_hobject(thr, -1);
+ DUK_ASSERT(func != NULL);
/*
* For bound objects, [[HasInstance]] just calls the target function
* [[HasInstance]]. If that is again a bound object, repeat until
* we find a non-bound Function object.
+ *
+ * The bound function chain is now "collapsed" so there can be only
+ * one bound function in the chain.
*/
- /* XXX: this bound function resolution also happens elsewhere,
- * move into a shared helper.
- */
-
- sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
- do {
- /* check func supports [[HasInstance]] (this is checked for every function
- * in the bound chain, including the final one)
+ if (!DUK_HOBJECT_IS_CALLABLE(func)) {
+ /*
+ * Note: of native Ecmascript objects, only Function instances
+ * have a [[HasInstance]] internal property. Custom objects might
+ * also have it, but not in current implementation.
+ *
+ * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
*/
+ goto error_invalid_rval;
+ }
- if (!DUK_HOBJECT_IS_CALLABLE(func)) {
- /*
- * Note: of native Ecmascript objects, only Function instances
- * have a [[HasInstance]] internal property. Custom objects might
- * also have it, but not in current implementation.
- *
- * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
- */
- DUK_ERROR_TYPE(thr, "invalid instanceof rval");
- }
-
- if (!DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
- break;
- }
-
- /* [ ... lval rval ] */
-
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */
- duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */
- func = duk_require_hobject(ctx, -1);
-
- /* func support for [[HasInstance]] checked in the beginning of the loop */
- } while (--sanity > 0);
+ if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
+ duk_push_tval(thr, &((duk_hboundfunc *) func)->target);
+ duk_replace(thr, -2);
+ func = duk_require_hobject(thr, -1); /* lightfunc throws */
- if (DUK_UNLIKELY(sanity == 0)) {
- DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
+ /* Rely on Function.prototype.bind() never creating bound
+ * functions whose target is not proper.
+ */
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
}
/*
@@ -76572,6 +78129,7 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
* to execute E5 Section 15.3.5.3.
*/
+ DUK_ASSERT(func != NULL);
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
@@ -76581,7 +78139,7 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
* from the virtual prototype object.
*/
skip_first = 0;
- tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
+ tv = DUK_GET_TVAL_NEGIDX(thr, -2);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_LIGHTFUNC:
val = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
@@ -76601,13 +78159,22 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
DUK_ASSERT(val != NULL);
break;
default:
- goto pop_and_false;
+ goto pop2_and_false;
}
DUK_ASSERT(val != NULL); /* Loop doesn't actually rely on this. */
- duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
- proto = duk_require_hobject(ctx, -1);
- duk_pop(ctx); /* -> [ ... lval rval ] */
+ /* Look up .prototype of rval. Leave it on the value stack in case it
+ * has been virtualized (e.g. getter, Proxy trap).
+ */
+ duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ proto = duk_get_hobject(thr, -1);
+ if (proto == NULL) {
+ goto error_invalid_rval_noproto;
+ }
+#else
+ proto = duk_require_hobject(thr, -1);
+#endif
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
do {
@@ -76630,18 +78197,18 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
*/
if (!val) {
- goto pop_and_false;
+ goto pop3_and_false;
}
DUK_ASSERT(val != NULL);
#if defined(DUK_USE_ES6_PROXY)
- val = duk_hobject_resolve_proxy_target(thr, val);
+ val = duk_hobject_resolve_proxy_target(val);
#endif
if (skip_first) {
skip_first = 0;
} else if (val == proto) {
- goto pop_and_true;
+ goto pop3_and_true;
}
DUK_ASSERT(val != NULL);
@@ -76653,13 +78220,27 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
}
DUK_UNREACHABLE();
- pop_and_false:
- duk_pop_2(ctx);
+ pop2_and_false:
+ duk_pop_2_unsafe(thr);
return 0;
- pop_and_true:
- duk_pop_2(ctx);
+ pop3_and_false:
+ duk_pop_3_unsafe(thr);
+ return 0;
+
+ pop3_and_true:
+ duk_pop_3_unsafe(thr);
return 1;
+
+ error_invalid_rval:
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL);
+ return 0;
+
+#if defined(DUK_USE_VERBOSE_ERRORS)
+ error_invalid_rval_noproto:
+ DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO);
+ return 0;
+#endif
}
/*
@@ -76673,7 +78254,6 @@ DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_
*/
DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
- duk_context *ctx = (duk_context *) thr;
duk_bool_t retval;
/*
@@ -76693,17 +78273,17 @@ DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv
/* TypeError if rval is not an object or object like (e.g. lightfunc
* or plain buffer).
*/
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
+ duk_push_tval(thr, tv_x);
+ duk_push_tval(thr, tv_y);
+ duk_require_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
- (void) duk_to_property_key_hstring(ctx, -2);
+ (void) duk_to_property_key_hstring(thr, -2);
retval = duk_hobject_hasprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- DUK_GET_TVAL_NEGIDX(ctx, -2));
+ DUK_GET_TVAL_NEGIDX(thr, -1),
+ DUK_GET_TVAL_NEGIDX(thr, -2));
- duk_pop_2(ctx);
+ duk_pop_2_unsafe(thr);
return retval;
}
@@ -76891,8 +78471,8 @@ DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *
/* Scanning to NUL is always safe for interned strings. */
break;
}
- DUK_ASSERT(t >= DUK_ASC_0 && t <= DUK_ASC_9);
- res = res * 10U + (t - DUK_ASC_0);
+ DUK_ASSERT(t >= (duk_uint8_t) DUK_ASC_0 && t <= (duk_uint8_t) DUK_ASC_9);
+ res = res * 10U + (duk_uarridx_t) t - (duk_uarridx_t) DUK_ASC_0;
}
return res;
}
@@ -76947,7 +78527,7 @@ typedef struct {
duk_hobject *env;
duk_hobject *holder; /* for object-bound identifiers */
duk_tval *value; /* for register-bound and declarative env identifiers */
- duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */
+ duk_uint_t attrs; /* property attributes for identifier (relevant if value != NULL) */
duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */
} duk__id_lookup_result;
@@ -77033,7 +78613,6 @@ void duk_js_push_closure(duk_hthread *thr,
duk_hobject *outer_var_env,
duk_hobject *outer_lex_env,
duk_bool_t add_auto_proto) {
- duk_context *ctx = (duk_context *) thr;
duk_hcompfunc *fun_clos;
duk_small_uint_t i;
duk_uint_t len_value;
@@ -77046,11 +78625,11 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_ASSERT(outer_lex_env != NULL);
DUK_UNREF(len_value);
- fun_clos = duk_push_hcompfunc(ctx);
+ fun_clos = duk_push_hcompfunc(thr);
DUK_ASSERT(fun_clos != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) fun_clos) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
- duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
+ duk_push_hobject(thr, &fun_temp->obj); /* -> [ ... closure template ] */
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun_clos));
DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) == NULL);
@@ -77080,10 +78659,14 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) != NULL);
DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) != NULL);
- /* XXX: could also copy from template, but there's no way to have any
+ /* XXX: Could also copy from template, but there's no way to have any
* other value here now (used code has no access to the template).
+ * Prototype is set by duk_push_hcompfunc().
*/
+ DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#if 0
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
+#endif
/* Copy duk_hobject flags as is from the template using a mask.
* Leave out duk_heaphdr owned flags just in case (e.g. if there's
@@ -77158,7 +78741,7 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
- duk_push_hobject(ctx, (duk_hobject *) new_env);
+ duk_push_hobject(thr, (duk_hobject *) new_env);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, proto);
@@ -77176,10 +78759,10 @@ void duk_js_push_closure(duk_hthread *thr,
* the name 'undefined' gets bound and maps to the closure (which is
* a bit odd, but safe).
*/
- (void) duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME);
+ (void) duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
/* -> [ ... closure template env funcname ] */
- duk_dup_m4(ctx); /* -> [ ... closure template env funcname closure ] */
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
+ duk_dup_m4(thr); /* -> [ ... closure template env funcname closure ] */
+ duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
/* env[funcname] = closure */
/* [ ... closure template env ] */
@@ -77188,7 +78771,7 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env);
DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
/* [ ... closure template ] */
}
@@ -77242,18 +78825,18 @@ void duk_js_push_closure(duk_hthread *thr,
/* [ ... closure template ] */
DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
- if (duk_get_prop_stridx_short(ctx, -1, stridx)) {
+ if (duk_get_prop_stridx_short(thr, -1, stridx)) {
/* [ ... closure template val ] */
DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
- duk_xdef_prop_stridx_short(ctx, -3, stridx, DUK_PROPDESC_FLAGS_C);
+ duk_xdef_prop_stridx_short(thr, -3, stridx, DUK_PROPDESC_FLAGS_C);
} else {
DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
}
@@ -77269,18 +78852,18 @@ void duk_js_push_closure(duk_hthread *thr,
/* XXX: these lookups should be just own property lookups instead of
* looking up the inheritance chain.
*/
- if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FORMALS)) {
+ if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS)) {
/* [ ... closure template formals ] */
- len_value = (duk_uint_t) duk_get_length(ctx, -1); /* could access duk_harray directly, not important */
+ len_value = (duk_uint_t) duk_get_length(thr, -1); /* could access duk_harray directly, not important */
DUK_DD(DUK_DDPRINT("closure length from _Formals -> %ld", (long) len_value));
} else {
len_value = fun_temp->nargs;
DUK_DD(DUK_DDPRINT("closure length defaulted from nargs -> %ld", (long) len_value));
}
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
- duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
- duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
+ duk_push_uint(thr, len_value); /* [ ... closure template len_value ] */
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
/*
* "prototype" is, by default, a fresh object with the "constructor"
@@ -77299,11 +78882,11 @@ void duk_js_push_closure(duk_hthread *thr,
/* [ ... closure template ] */
if (add_auto_proto) {
- duk_push_object(ctx); /* -> [ ... closure template newobj ] */
- duk_dup_m3(ctx); /* -> [ ... closure template newobj closure ] */
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
- duk_compact(ctx, -1); /* compact the prototype */
- duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
+ duk_push_object(thr); /* -> [ ... closure template newobj ] */
+ duk_dup_m3(thr); /* -> [ ... closure template newobj closure ] */
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
+ duk_compact(thr, -1); /* compact the prototype */
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
}
/*
@@ -77317,13 +78900,13 @@ void duk_js_push_closure(duk_hthread *thr,
/* [ ... closure template ] */
if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
- duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_CALLER);
- duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_LC_ARGUMENTS);
+ duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_CALLER);
+ duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_LC_ARGUMENTS);
} else {
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
- duk_push_null(ctx);
- duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
+ duk_push_null(thr);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
#else
DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
#endif
@@ -77340,18 +78923,18 @@ void duk_js_push_closure(duk_hthread *thr,
/* XXX: Look for own property only; doesn't matter much because
* templates are bare objects.
*/
- if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME)) {
+ if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME)) {
/* [ ... closure template name ] */
- DUK_ASSERT(duk_is_string(ctx, -1));
- DUK_DD(DUK_DDPRINT("setting function instance name to %!T", duk_get_tval(ctx, -1)));
- duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); /* -> [ ... closure template ] */
+ DUK_ASSERT(duk_is_string(thr, -1));
+ DUK_DD(DUK_DDPRINT("setting function instance name to %!T", duk_get_tval(thr, -1)));
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); /* -> [ ... closure template ] */
} else {
/* Anonymous functions don't have a .name in ES2015, so don't set
* it on the instance either. The instance will then inherit
* it from Function.prototype.name.
*/
DUK_DD(DUK_DDPRINT("not setting function instance .name"));
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
#endif
@@ -77364,7 +78947,7 @@ void duk_js_push_closure(duk_hthread *thr,
* through the API).
*/
- duk_compact(ctx, -2);
+ duk_compact(thr, -2);
/*
* Some assertions (E5 Section 13.2).
@@ -77373,13 +78956,13 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
- DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH) != 0);
- DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
+ DUK_ASSERT(duk_has_prop_stridx(thr, -2, DUK_STRIDX_LENGTH) != 0);
+ DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(thr, -2, DUK_STRIDX_PROTOTYPE) != 0);
/* May be missing .name */
DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
- duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
+ duk_has_prop_stridx(thr, -2, DUK_STRIDX_CALLER) != 0);
DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
- duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
+ duk_has_prop_stridx(thr, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
/*
* Finish
@@ -77388,10 +78971,10 @@ void duk_js_push_closure(duk_hthread *thr,
/* [ ... closure template ] */
DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
- (duk_tval *) duk_get_tval(ctx, -1),
- (duk_tval *) duk_get_tval(ctx, -2)));
+ (duk_tval *) duk_get_tval(thr, -1),
+ (duk_tval *) duk_get_tval(thr, -2)));
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
/* [ ... closure ] */
}
@@ -77407,13 +78990,11 @@ void duk_js_push_closure(duk_hthread *thr,
DUK_INTERNAL
duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
duk_hobject *func,
- duk_size_t idx_bottom) {
- duk_context *ctx = (duk_context *) thr;
+ duk_size_t bottom_byteoff) {
duk_hdecenv *env;
duk_hobject *parent;
duk_hcompfunc *f;
- DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(func != NULL);
@@ -77427,7 +79008,7 @@ duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(env != NULL);
- duk_push_hobject(ctx, (duk_hobject *) env);
+ duk_push_hobject(thr, (duk_hobject *) env);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent);
@@ -77437,7 +79018,7 @@ duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
DUK_ASSERT(env->thread == NULL);
DUK_ASSERT(env->varmap == NULL);
- DUK_ASSERT(env->regbase == 0);
+ DUK_ASSERT(env->regbase_byteoff == 0);
if (DUK_HOBJECT_IS_COMPFUNC(func)) {
duk_hobject *varmap;
duk_tval *tv;
@@ -77451,12 +79032,12 @@ duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
DUK_HOBJECT_INCREF(thr, varmap);
env->thread = thr;
DUK_HTHREAD_INCREF(thr, thr);
- env->regbase = idx_bottom;
+ env->regbase_byteoff = bottom_byteoff;
} else {
/* If function has no _Varmap, leave the environment closed. */
DUK_ASSERT(env->thread == NULL);
DUK_ASSERT(env->varmap == NULL);
- DUK_ASSERT(env->regbase == 0);
+ DUK_ASSERT(env->regbase_byteoff == 0);
}
}
@@ -77466,13 +79047,10 @@ duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
DUK_INTERNAL
void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
duk_activation *act) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *func;
duk_hobject *env;
- duk_size_t act_off;
- DUK_ASSERT(act != NULL);
- act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
+ DUK_ASSERT(thr != NULL);
func = DUK_ACT_GET_FUNC(act);
DUK_ASSERT(func != NULL);
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */
@@ -77485,9 +79063,9 @@ void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
DUK_ASSERT(act->lex_env == NULL);
DUK_ASSERT(act->var_env == NULL);
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
+ env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
DUK_ASSERT(env != NULL);
- act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off);
+ /* 'act' is a stable pointer, so still OK. */
DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
@@ -77505,7 +79083,7 @@ void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
DUK_HOBJECT_INCREF(thr, env);
- duk_pop(ctx);
+ duk_pop_unsafe(thr);
}
/*
@@ -77517,7 +79095,6 @@ void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
*/
DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) {
- duk_context *ctx = (duk_context *) thr;
duk_uint_fast32_t i;
duk_hobject *varmap;
duk_hstring *key;
@@ -77570,7 +79147,7 @@ DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject
* then realloc with hash part if large enough).
*/
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
- duk_size_t regbase;
+ duk_size_t regbase_byteoff;
key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */
@@ -77586,19 +79163,19 @@ DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject
regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
#endif
- regbase = ((duk_hdecenv *) env)->regbase;
- DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
- DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
+ regbase_byteoff = ((duk_hdecenv *) env)->regbase_byteoff;
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum >= (duk_uint8_t *) thr->valstack);
+ DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum < (duk_uint8_t *) thr->valstack_top);
/* If property already exists, overwrites silently.
* Property is writable, but not deletable (not configurable
* in terms of property attributes).
*/
- duk_push_tval(ctx, thr->valstack + regbase + regnum);
+ duk_push_tval(thr, (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum));
DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T",
(duk_heaphdr *) key,
(long) regnum,
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -1)));
duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE);
}
@@ -77642,7 +79219,6 @@ duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
duk__id_lookup_result *out) {
duk_tval *tv;
duk_size_t reg_rel;
- duk_size_t idx;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(name != NULL);
@@ -77673,8 +79249,7 @@ duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
#endif
DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
- idx = env->regbase + reg_rel;
- tv = env->thread->valstack + idx;
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) env->thread->valstack + env->regbase_byteoff + sizeof(duk_tval) * reg_rel);
DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */
out->value = tv;
@@ -77695,7 +79270,6 @@ duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
duk_hobject *func;
duk_hobject *varmap;
duk_size_t reg_rel;
- duk_size_t idx;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(name != NULL);
@@ -77728,9 +79302,8 @@ duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
DUK_ASSERT_DISABLE(reg_rel >= 0);
DUK_ASSERT(reg_rel < ((duk_hcompfunc *) func)->nregs);
- idx = act->idx_bottom + reg_rel;
- DUK_ASSERT(idx >= act->idx_bottom);
- tv = thr->valstack + idx;
+ tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
+ tv += reg_rel;
out->value = tv;
out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
@@ -77748,7 +79321,6 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
duk_bool_t parents,
duk__id_lookup_result *out) {
duk_tval *tv;
- duk_tval tv_name;
duk_uint_t sanity;
DUK_ASSERT(thr != NULL);
@@ -77841,8 +79413,8 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
while (env != NULL) {
- duk_small_int_t cl;
- duk_int_t attrs;
+ duk_small_uint_t cl;
+ duk_uint_t attrs;
DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
(duk_heaphdr *) name,
@@ -77926,7 +79498,9 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
* property is found, but rather the object binding target object.
*/
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) {
+#if defined(DUK_USE_ES6_PROXY)
+ if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(target))) {
+ duk_tval tv_name;
duk_tval tv_target_tmp;
DUK_ASSERT(name != NULL);
@@ -77934,7 +79508,9 @@ duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
DUK_TVAL_SET_OBJECT(&tv_target_tmp, target);
found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name);
- } else {
+ } else
+#endif /* DUK_USE_ES6_PROXY */
+ {
/* XXX: duk_hobject_hasprop() would be correct for
* non-Proxy objects too, but it is about ~20-25%
* slower at present so separate code paths for
@@ -78056,7 +79632,6 @@ duk_bool_t duk__getvar_helper(duk_hthread *thr,
duk_activation *act,
duk_hstring *name,
duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
duk__id_lookup_result ref;
duk_tval tv_tmp_obj;
duk_tval tv_tmp_key;
@@ -78071,14 +79646,16 @@ duk_bool_t duk__getvar_helper(duk_hthread *thr,
DUK_ASSERT(name != NULL);
/* env and act may be NULL */
+ DUK_STATS_INC(thr->heap, stats_getvar_all);
+
DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
parents = 1; /* follow parent chain */
if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
if (ref.value) {
- duk_push_tval(ctx, ref.value);
- duk_push_undefined(ctx);
+ duk_push_tval(thr, ref.value);
+ duk_push_undefined(thr);
} else {
DUK_ASSERT(ref.holder != NULL);
@@ -78092,9 +79669,9 @@ duk_bool_t duk__getvar_helper(duk_hthread *thr,
(void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */
if (ref.has_this) {
- duk_push_hobject(ctx, ref.holder);
+ duk_push_hobject(thr, ref.holder);
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
/* [value this] */
@@ -78156,6 +79733,8 @@ void duk__putvar_helper(duk_hthread *thr,
duk_tval tv_tmp_key;
duk_bool_t parents;
+ DUK_STATS_INC(thr->heap, stats_putvar_all);
+
DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
"(env -> %!dO, val -> %!T)",
(void *) thr, (void *) env, (void *) act,
@@ -78398,9 +79977,8 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
duk_hobject *env,
duk_hstring *name,
duk_tval *val,
- duk_small_int_t prop_flags,
+ duk_small_uint_t prop_flags,
duk_bool_t is_func_decl) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *holder;
duk_bool_t parents;
duk__id_lookup_result ref;
@@ -78441,7 +80019,7 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
duk_int_t e_idx;
duk_int_t h_idx;
- duk_small_int_t flags;
+ duk_small_uint_t flags;
/*
* Variable already declared, ignore re-declaration.
@@ -78488,8 +80066,8 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
/* must be found: was found earlier, and cannot be inherited */
for (;;) {
DUK_ASSERT(holder != NULL);
- duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx);
- if (e_idx >= 0) {
+ if (duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx)) {
+ DUK_ASSERT(e_idx >= 0);
break;
}
/* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
@@ -78568,7 +80146,7 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
- duk_push_tval(ctx, val);
+ duk_push_tval(thr, val);
duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
}
@@ -78608,11 +80186,11 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
goto fail_not_extensible;
}
- duk_push_hobject(ctx, holder);
- duk_push_hstring(ctx, name);
- duk_push_tval(ctx, val);
- duk_xdef_prop(ctx, -3, prop_flags); /* [holder name val] -> [holder] */
- duk_pop(ctx);
+ duk_push_hobject(thr, holder);
+ duk_push_hstring(thr, name);
+ duk_push_tval(thr, val);
+ duk_xdef_prop(thr, -3, prop_flags); /* [holder name val] -> [holder] */
+ duk_pop_unsafe(thr);
return 0;
@@ -78627,14 +80205,12 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
duk_activation *act,
duk_hstring *name,
duk_tval *val,
- duk_small_int_t prop_flags,
+ duk_small_uint_t prop_flags,
duk_bool_t is_func_decl) {
duk_hobject *env;
duk_tval tv_val_copy;
- duk_size_t act_off;
DUK_ASSERT(act != NULL);
- act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
/*
* Make a value copy of the input val. This ensures that
@@ -78651,7 +80227,7 @@ duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
if (!act->var_env) {
DUK_ASSERT(act->lex_env == NULL);
duk_js_init_activation_environment_records_delayed(thr, act);
- act = (duk_activation *) (void *) ((duk_uint8_t *) thr->callstack + act_off);
+ /* 'act' is a stable pointer, so still OK. */
}
DUK_ASSERT(act->lex_env != NULL);
DUK_ASSERT(act->var_env != NULL);
@@ -78976,7 +80552,7 @@ DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t s
lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
lex_ctx->input_line = input_line;
- DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
}
DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
@@ -79136,7 +80712,7 @@ DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
error_clipped: /* clipped codepoint */
error_encoding: /* invalid codepoint encoding or codepoint */
- DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_DECODE_FAILED);
+ DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
return 0;
}
@@ -79225,13 +80801,11 @@ DUK_LOCAL void duk__appendbuffer_ascii(duk_lexer_ctx *lex_ctx, duk_codepoint_t x
*/
DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
- duk_context *ctx = (duk_context *) lex_ctx->thr;
-
DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
- duk_replace(ctx, valstack_idx);
- return duk_known_hstring(ctx, valstack_idx);
+ duk_replace(lex_ctx->thr, valstack_idx);
+ return duk_known_hstring(lex_ctx->thr, valstack_idx);
}
/*
@@ -79319,7 +80893,7 @@ DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bo
duk_small_int_t digits; /* Initial value 2 or 4 for fixed length escapes, 0 for ES2015 \u{H+}. */
duk_codepoint_t escval;
duk_codepoint_t x;
- duk_small_int_t adv;
+ duk_small_uint_t adv;
DUK_ASSERT(DUK__L0() == DUK_ASC_BACKSLASH); /* caller responsibilities */
DUK_ASSERT(DUK__L1() == DUK_ASC_LC_X || DUK__L1() == DUK_ASC_LC_U);
@@ -79413,10 +80987,10 @@ DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bo
* RegExp octal escape parsing. Window[0] must be the slash '\' and the first
* digit must already be validated to be in [0-9] by the caller.
*/
-DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_int_t *out_adv, duk_bool_t reject_annex_b) {
+DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_uint_t *out_adv, duk_bool_t reject_annex_b) {
duk_codepoint_t cp;
duk_small_uint_t lookup_idx;
- duk_small_int_t adv;
+ duk_small_uint_t adv;
duk_codepoint_t tmp;
DUK_ASSERT(out_adv != NULL);
@@ -79424,6 +80998,7 @@ DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx,
DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9);
cp = 0;
+ tmp = 0;
for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) {
DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp));
tmp = DUK__LOOKUP(lex_ctx, lookup_idx);
@@ -79472,7 +81047,7 @@ DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx,
/* XXX: move strict mode to lex_ctx? */
DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) {
- duk_small_int_t adv;
+ duk_small_uint_t adv;
for (adv = 1 /* initial quote */ ;;) {
duk_codepoint_t x;
@@ -79701,7 +81276,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
}
out_token->t = DUK_TOK_EOF;
- out_token->t_nores = -1; /* marker: copy t if not changed */
+ out_token->t_nores = DUK_TOK_INVALID; /* marker: copy t if not changed */
#if 0 /* not necessary to init, disabled for faster parsing */
out_token->num = DUK_DOUBLE_NAN;
out_token->str1 = NULL;
@@ -79716,8 +81291,8 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
* freed normally.
*/
#if 0
- duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
- duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
+ duk_to_undefined(lex_ctx->thr, lex_ctx->slot1_idx);
+ duk_to_undefined(lex_ctx->thr, lex_ctx->slot2_idx);
#endif
/* 'advtok' indicates how much to advance and which token id to assign
@@ -79966,7 +81541,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
#if defined(DUK_USE_HTML_COMMENTS)
if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) {
/*
- * ES6: B.1.3, handle "<!--" SingleLineHTMLOpenComment
+ * ES2015: B.1.3, handle "<!--" SingleLineHTMLOpenComment
*/
/* DUK__ADVANCECHARS(lex_ctx, 4) would be correct here, but not necessary */
@@ -80031,7 +81606,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
#if defined(DUK_USE_HTML_COMMENTS)
if (got_lineterm && DUK__L1() == DUK_ASC_MINUS && DUK__L2() == DUK_ASC_RANGLE) {
/*
- * ES6: B.1.3, handle "-->" SingleLineHTMLCloseComment
+ * ES2015: B.1.3, handle "-->" SingleLineHTMLCloseComment
* Only allowed:
* - on new line
* - preceded only by whitespace
@@ -80115,7 +81690,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
DUK__INITBUFFER(lex_ctx);
duk__lexer_parse_string_literal(lex_ctx, out_token, x /*quote*/, strict_mode);
duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- out_token->str1 = duk_known_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
+ out_token->str1 = duk_known_hstring(lex_ctx->thr, lex_ctx->slot1_idx);
DUK__INITBUFFER(lex_ctx); /* free some memory */
@@ -80174,7 +81749,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
* parsing the identifier. This has little practical impact.
*/
- duk_small_int_t i, i_end;
+ duk_small_uint_t i, i_end;
duk_bool_t first = 1;
duk_hstring *str;
@@ -80246,7 +81821,8 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
if (out_token->num_escapes == 0) {
for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
- DUK_ASSERT(i >= 0 && i < DUK_HEAP_NUM_STRINGS);
+ DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
+ DUK_ASSERT(i < DUK_HEAP_NUM_STRINGS);
if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
break;
@@ -80287,7 +81863,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
*/
duk_small_uint_t s2n_flags;
duk_codepoint_t y, z;
- duk_small_uint_t s2n_radix = 10;
+ duk_small_int_t s2n_radix = 10;
duk_small_uint_t pre_adv = 0;
DUK__INITBUFFER(lex_ctx);
@@ -80393,13 +81969,13 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
}
- duk_dup((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
- duk_numconv_parse((duk_context *) lex_ctx->thr, s2n_radix, s2n_flags);
- val = duk_to_number_m1((duk_context *) lex_ctx->thr);
+ duk_dup(lex_ctx->thr, lex_ctx->slot1_idx);
+ duk_numconv_parse(lex_ctx->thr, s2n_radix, s2n_flags);
+ val = duk_to_number_m1(lex_ctx->thr);
if (DUK_ISNAN(val)) {
goto fail_number_literal;
}
- duk_replace((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
+ duk_replace(lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
DUK__INITBUFFER(lex_ctx); /* free some memory */
@@ -80429,7 +82005,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
out_token->t = advtok & 0xff;
- if (out_token->t_nores < 0) {
+ if (out_token->t_nores == DUK_TOK_INVALID) {
out_token->t_nores = out_token->t;
}
out_token->lineterm = got_lineterm;
@@ -80489,7 +82065,7 @@ void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
*/
DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
- duk_small_int_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
+ duk_small_uint_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
duk_codepoint_t x, y;
if (++lex_ctx->token_count >= lex_ctx->token_limit) {
@@ -80554,8 +82130,8 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
}
case DUK_ASC_LCURLY: {
/* Production allows 'DecimalDigits', including leading zeroes */
- duk_uint_fast32_t val1 = 0;
- duk_uint_fast32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
+ duk_uint32_t val1 = 0;
+ duk_uint32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
duk_small_int_t digits = 0;
#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
duk_lexer_point lex_pt;
@@ -80571,7 +82147,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
x = DUK__L0();
if (DUK__ISDIGIT(x)) {
digits++;
- val1 = val1 * 10 + (duk_uint_fast32_t) duk__hexval(x);
+ val1 = val1 * 10 + (duk_uint32_t) duk__hexval(x);
} else if (x == DUK_ASC_COMMA) {
if (digits > DUK__MAX_RE_QUANT_DIGITS) {
goto invalid_quantifier;
@@ -80667,7 +82243,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
x = DUK__L2();
if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
(x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
- out_token->num = (x % 32);
+ out_token->num = (duk_uint32_t) (x % 32);
advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
} else {
goto fail_escape;
@@ -80678,7 +82254,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
* here. The \u{H+} is only allowed in Unicode mode
* which we don't support yet.
*/
- out_token->num = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
+ out_token->num = (duk_uint32_t) duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_CHAR);
} else if (y == DUK_ASC_LC_D) {
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
@@ -80702,7 +82278,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
} else {
/* XXX: shared parsing? */
- duk_uint_fast32_t val = 0;
+ duk_uint32_t val = 0;
duk_small_int_t i;
for (i = 0; ; i++) {
if (i >= DUK__MAX_RE_DECESC_DIGITS) {
@@ -80713,7 +82289,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
if (!DUK__ISDIGIT(x)) {
break;
}
- val = val * 10 + (duk_uint_fast32_t) duk__hexval(x);
+ val = val * 10 + (duk_uint32_t) duk__hexval(x);
}
/* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
@@ -80739,7 +82315,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
* test-regexp-identity-escape-dollar.js.
*/
#endif /* DUK_USE_ES6_REGEXP_SYNTAX */
- out_token->num = y;
+ out_token->num = (duk_uint32_t) y;
} else {
goto fail_escape;
}
@@ -80806,7 +82382,7 @@ DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token
default: {
/* PatternCharacter, all excluded characters are matched by cases above */
advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
- out_token->num = x;
+ out_token->num = (duk_uint32_t) x;
break;
}
}
@@ -80885,7 +82461,7 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
duk_codepoint_t ch;
duk_codepoint_t x;
duk_bool_t dash = 0;
- duk_small_int_t adv = 0;
+ duk_small_uint_t adv = 0;
DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
@@ -80907,7 +82483,7 @@ DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range
DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */
break;
} else if (x == DUK_ASC_MINUS) {
- if (start >= 0 && !dash && DUK__L0() != DUK_ASC_RBRACKET) {
+ if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) {
/* '-' as a range indicator */
dash = 1;
continue;
@@ -81259,7 +82835,7 @@ DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
if (n == 0) {
return;
}
- DUK_MEMCPY((void *) x->v, (const 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) * (size_t) n));
}
DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
@@ -81444,7 +83020,7 @@ DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
tz = 0;
}
tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
- x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
+ x->v[i] = (duk_uint32_t) ((duk_uint64_t) tmp & 0xffffffffUL);
tmp = tmp >> 32; /* 0 or -1 */
}
DUK_ASSERT(tmp == 0);
@@ -81535,7 +83111,7 @@ DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
return;
}
- DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * nx));
+ DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx));
x->n = nx;
nz = z->n;
@@ -81685,7 +83261,7 @@ DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
n = (y / 32) + 1;
DUK_ASSERT(n > 0);
r = y % 32;
- DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * n);
+ DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * (size_t) n);
x->n = n;
x->v[n - 1] = (((duk_uint32_t) 1) << r);
}
@@ -81708,7 +83284,7 @@ DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_in
DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
duk__bi_set_small(x, 1);
- duk__bi_set_small(t1, b);
+ duk__bi_set_small(t1, (duk_uint32_t) b);
for (;;) {
/* Loop structure ensures that we don't compute t1^2 unnecessarily
* on the final round, as that might create a bignum exceeding the
@@ -81749,10 +83325,10 @@ DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_in
*/
/* Maximum number of digits generated. */
-#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + spare */
+#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + slack */
/* Maximum number of characters in formatted value. */
-#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + spare */
+#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + slack */
/* Number and (minimum) size of bigints in the nc_ctx structure. */
#define DUK__NUMCONV_CTX_NUM_BIGINTS 7
@@ -81797,7 +83373,7 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x
duk_uint8_t *p;
duk_size_t len;
duk_small_int_t dig;
- duk_small_int_t t;
+ duk_uint32_t t;
DUK_ASSERT(radix >= 2 && radix <= 36);
@@ -81808,8 +83384,8 @@ DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x
p = buf + 32;
for (;;) {
- t = x / radix;
- dig = x - t * radix;
+ t = x / (duk_uint32_t) radix;
+ dig = (duk_small_int_t) (x - t * (duk_uint32_t) radix);
x = t;
DUK_ASSERT(dig >= 0 && dig < 36);
@@ -81889,10 +83465,10 @@ DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
"unequal gaps"));
duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
- duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, nc_ctx->b); /* mp <- b^(e+1) */
+ duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, (duk_uint32_t) nc_ctx->b); /* mp <- b^(e+1) */
duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
- duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
- duk__bi_set_small(&nc_ctx->s, nc_ctx->b * 2); /* s <- 2 * b */
+ duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
+ duk__bi_set_small(&nc_ctx->s, (duk_uint32_t) (nc_ctx->b * 2)); /* s <- 2 * b */
nc_ctx->unequal_gaps = 1;
} else {
/* (>= e 0) AND (not (= f (expt b (- p 1))))
@@ -81938,7 +83514,7 @@ DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
"lowest mantissa for this exponent -> "
"unequal gaps"));
- duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, nc_ctx->b * 2); /* r <- (2 * b) * f */
+ duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, (duk_uint32_t) (nc_ctx->b * 2)); /* r <- (2 * b) * f */
duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, 1 - nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */
duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */
duk__bi_set_small(&nc_ctx->mp, 2);
@@ -82017,7 +83593,7 @@ DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
* k <- (+ k 1)
*/
- duk__bi_mul_small_copy(&nc_ctx->s, nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->s, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
k++;
} else {
break;
@@ -82037,7 +83613,7 @@ DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
DUK__BI_PRINT("m-", &nc_ctx->mm);
duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
- duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, nc_ctx->B); /* t2 = (* (+ r m+) B) */
+ duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, (duk_uint32_t) nc_ctx->B); /* t2 = (* (+ r m+) B) */
if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
DUK_DDD(DUK_DDDPRINT("k is too high"));
/* r <- (* r B)
@@ -82046,11 +83622,11 @@ DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
* m- <- (* m- B)
* k <- (- k 1)
*/
- duk__bi_mul_small_copy(&nc_ctx->r, nc_ctx->B, &nc_ctx->t1);
- duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->r, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
if (nc_ctx->unequal_gaps) {
DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
- duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
}
k--;
} else {
@@ -82106,7 +83682,7 @@ DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
DUK__BI_PRINT("m-", &nc_ctx->mm);
/* (quotient-remainder (* r B) s) using a dummy subtraction loop */
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, nc_ctx->B); /* t1 <- (* r B) */
+ duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, (duk_uint32_t) nc_ctx->B); /* t1 <- (* r B) */
d = 0;
for (;;) {
if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
@@ -82120,8 +83696,8 @@ DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
DUK__BI_PRINT("r(rem)", &nc_ctx->r);
- duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
- duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
+ duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
+ duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
@@ -82291,7 +83867,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
(const void *) (&nc_ctx->digits[0]),
- (size_t) (sizeof(char) * nc_ctx->count));
+ (size_t) (sizeof(char) * (size_t) nc_ctx->count));
nc_ctx->digits[0] = 1; /* don't increase 'count' */
nc_ctx->k++; /* position of highest digit changed */
nc_ctx->count++; /* number of digits changed */
@@ -82320,11 +83896,11 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */
DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
- duk_context *ctx,
- duk_small_int_t radix,
- duk_small_int_t digits,
- duk_small_uint_t flags,
- duk_small_int_t neg) {
+ duk_hthread *thr,
+ duk_small_int_t radix,
+ duk_small_int_t digits,
+ duk_small_uint_t flags,
+ duk_small_int_t neg) {
duk_small_int_t k;
duk_small_int_t pos, pos_end;
duk_small_int_t expt;
@@ -82460,7 +84036,7 @@ DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
q += len;
}
- duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
+ duk_push_lstring(thr, (const char *) buf, (size_t) (q - buf));
}
/*
@@ -82639,7 +84215,7 @@ DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, du
(unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
- t += expt << 20;
+ t += ((duk_uint32_t) expt) << 20;
#if 0 /* caller handles sign change */
if (negative) {
t |= 0x80000000U;
@@ -82661,7 +84237,7 @@ DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, du
* Output: [ string ]
*/
-DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
+DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
duk_double_t x;
duk_small_int_t c;
duk_small_int_t neg;
@@ -82669,8 +84245,8 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
- x = (duk_double_t) duk_require_number(ctx, -1);
- duk_pop(ctx);
+ x = (duk_double_t) duk_require_number(thr, -1);
+ duk_pop(thr);
/*
* Handle special cases (NaN, infinity, zero).
@@ -82688,15 +84264,15 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
if (c == DUK_FP_NAN) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_NAN);
return;
} else if (c == DUK_FP_INFINITE) {
if (neg) {
/* -Infinity */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_INFINITY);
} else {
/* Infinity */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
+ duk_push_hstring_stridx(thr, DUK_STRIDX_INFINITY);
}
return;
} else if (c == DUK_FP_ZERO) {
@@ -82730,7 +84306,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
*p++ = (duk_uint8_t) '-';
}
p += duk__dragon4_format_uint32(p, uval, radix);
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
+ duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
return;
}
@@ -82789,7 +84365,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
}
DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
DUK_ASSERT(count >= 1);
- DUK_MEMZERO((void *) nc_ctx->digits, count);
+ DUK_MEMZERO((void *) nc_ctx->digits, (size_t) count);
nc_ctx->count = count;
nc_ctx->k = 1; /* 0.000... */
neg = 0;
@@ -82851,7 +84427,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
*/
}
- duk__dragon4_convert_and_push(nc_ctx, ctx, radix, digits, flags, neg);
+ duk__dragon4_convert_and_push(nc_ctx, thr, radix, digits, flags, neg);
}
/*
@@ -82864,8 +84440,7 @@ DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix,
* fails due to an internal error, an InternalError is thrown.
*/
-DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
+DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) {
duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
duk_double_t res;
@@ -82885,7 +84460,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
duk_small_int_t ch;
DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
- (duk_tval *) duk_get_tval(ctx, -1),
+ (duk_tval *) duk_get_tval(thr, -1),
(long) radix, (unsigned long) flags));
DUK_ASSERT(radix >= 2 && radix <= 36);
@@ -82917,9 +84492,9 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
* sometimes not. After white space trimming, all valid input
* characters are pure ASCII.
*/
- duk_trim(ctx, -1);
+ duk_trim(thr, -1);
}
- h_str = duk_require_hstring(ctx, -1);
+ h_str = duk_require_hstring(thr, -1);
DUK_ASSERT(h_str != NULL);
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
@@ -83158,8 +84733,8 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
/* XXX: join these ops (multiply-accumulate), but only if
* code footprint decreases.
*/
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
- duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
+ duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, (duk_uint32_t) radix);
+ duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, (duk_uint32_t) dig);
dig_prec++;
}
} else {
@@ -83281,7 +84856,7 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
* have enough (apparent) precision to work with.
*/
DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
- duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
+ duk__bi_mul_small_copy(&nc_ctx->f, (duk_uint32_t) radix, &nc_ctx->t1);
DUK__BI_PRINT("f", &nc_ctx->f);
expt--;
dig_prec++;
@@ -83369,15 +84944,15 @@ DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk
if (neg) {
res = -res;
}
- duk_pop(ctx);
- duk_push_number(ctx, (double) res);
- DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
+ duk_pop(thr);
+ duk_push_number(thr, (double) res);
+ DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
return;
parse_fail:
DUK_DDD(DUK_DDDPRINT("parse failed"));
- duk_pop(ctx);
- duk_push_nan(ctx);
+ duk_pop(thr);
+ duk_push_nan(thr);
return;
parse_explimit_error:
@@ -83486,7 +85061,8 @@ DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t
duk_small_int_t len;
len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
- DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, len);
+ DUK_ASSERT(len >= 0);
+ DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, (duk_size_t) len);
return (duk_uint32_t) len;
}
@@ -83628,71 +85204,213 @@ DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_
/*
* duk_re_range_callback for generating character class ranges.
*
- * When ignoreCase is false, the range is simply emitted as is.
- * We don't, for instance, eliminate duplicates or overlapping
- * ranges in a character class.
- *
- * When ignoreCase is true, the range needs to be normalized through
- * canonicalization. Unfortunately a canonicalized version of a
- * continuous range is not necessarily continuous (e.g. [x-{] is
- * continuous but [X-{] is not). The current algorithm creates the
- * canonicalized range(s) space efficiently at the cost of compile
- * time execution time (see doc/regexp.rst for discussion).
- *
- * Note that the ctx->nranges is a context-wide temporary value
- * (this is OK because there cannot be multiple character classes
- * being parsed simultaneously).
- */
+ * When ignoreCase is false, the range is simply emitted as is. We don't,
+ * for instance, eliminate duplicates or overlapping ranges in a character
+ * class.
+ *
+ * When ignoreCase is true but the 'direct' flag is set, the caller knows
+ * that the range canonicalizes to itself for case insensitive matching,
+ * so the range is emitted as is. This is mainly useful for built-in ranges
+ * like \W.
+ *
+ * Otherwise, when ignoreCase is true, the range needs to be normalized
+ * through canonicalization. Unfortunately a canonicalized version of a
+ * continuous range is not necessarily continuous (e.g. [x-{] is continuous
+ * but [X-{] is not). As a result, a single input range may expand to a lot
+ * of output ranges. The current algorithm creates the canonicalized ranges
+ * footprint efficiently at the cost of compile time execution time; see
+ * doc/regexp.rst for discussion, and some more details below.
+ *
+ * Note that the ctx->nranges is a context-wide temporary value. This is OK
+ * because there cannot be multiple character classes being parsed
+ * simultaneously.
+ *
+ * More detail on canonicalization:
+ *
+ * Conceptually, a range is canonicalized by scanning the entire range,
+ * normalizing each codepoint by converting it to uppercase, and generating
+ * a set of result ranges.
+ *
+ * Ideally a minimal set of output ranges would be emitted by merging all
+ * possible ranges even if they're emitted out of sequence. Because the
+ * input string is also case normalized during matching, some codepoints
+ * never occur at runtime; these "don't care" codepoints can be included or
+ * excluded from ranges when merging/optimizing ranges.
+ *
+ * The current algorithm does not do optimal range merging. Rather, output
+ * codepoints are generated in sequence, and when the output codepoints are
+ * continuous (CP, CP+1, CP+2, ...), they are merged locally into as large a
+ * range as possible. A small canonicalization bitmap is used to reduce
+ * actual codepoint canonicalizations which are quite slow at present. The
+ * bitmap provides a "codepoint block is continuous with respect to
+ * canonicalization" for N-codepoint blocks. This allows blocks to be
+ * skipped quickly.
+ *
+ * There are a number of shortcomings and future work here:
+ *
+ * - Individual codepoint normalizations are slow because they involve
+ * walking bit-packed rules without a lookup index.
+ *
+ * - The conceptual algorithm needs to canonicalize every codepoint in the
+ * input range to figure out the output range(s). Even with the small
+ * canonicalization bitmap the algorithm runs quite slowly for worst case
+ * inputs. There are many data structure alternatives to improve this.
+ *
+ * - While the current algorithm generates maximal output ranges when the
+ * output codepoints are emitted linearly, output ranges are not sorted or
+ * merged otherwise. In the worst case a lot of ranges are emitted when
+ * most of the ranges could be merged. In this process one could take
+ * advantage of "don't care" codepoints, which are never matched against at
+ * runtime due to canonicalization of input codepoints before comparison,
+ * to merge otherwise discontinuous output ranges.
+ *
+ * - The runtime data structure is just a linear list of ranges to match
+ * against. This can be quite slow if there are a lot of output ranges.
+ * There are various ways to make matching against the ranges faster,
+ * e.g. sorting the ranges and using a binary search; skip lists; tree
+ * based representations; full or approximate codepoint bitmaps, etc.
+ *
+ * - Only BMP is supported, codepoints above BMP are assumed to canonicalize
+ * to themselves. For now this is one place where we don't want to
+ * support chars outside the BMP, because the exhaustive search would be
+ * massively larger. It would be possible to support non-BMP with a
+ * different algorithm, or perhaps doing case normalization only at match
+ * time.
+ */
+
+DUK_LOCAL void duk__regexp_emit_range(duk_re_compiler_ctx *re_ctx, duk_codepoint_t r1, duk_codepoint_t r2) {
+ DUK_ASSERT(r2 >= r1);
+ duk__append_u32(re_ctx, (duk_uint32_t) r1);
+ duk__append_u32(re_ctx, (duk_uint32_t) r2);
+ re_ctx->nranges++;
+}
+
+#if defined(DUK_USE_REGEXP_CANON_BITMAP)
+/* Find next canonicalization discontinuity (conservative estimate) starting
+ * from 'start', not exceeding 'end'. If continuity is fine up to 'end'
+ * inclusive, returns end. Minimum possible return value is start.
+ */
+DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
+ duk_uint_t start_blk;
+ duk_uint_t end_blk;
+ duk_uint_t blk;
+ duk_uint_t offset;
+ duk_uint8_t mask;
+
+ /* Inclusive block range. */
+ DUK_ASSERT(start >= 0);
+ DUK_ASSERT(end >= 0);
+ DUK_ASSERT(end >= start);
+ start_blk = (duk_uint_t) (start >> DUK_CANON_BITMAP_BLKSHIFT);
+ end_blk = (duk_uint_t) (end >> DUK_CANON_BITMAP_BLKSHIFT);
+
+ for (blk = start_blk; blk <= end_blk; blk++) {
+ offset = blk >> 3;
+ mask = 1U << (blk & 0x07);
+ if (offset >= sizeof(duk_unicode_re_canon_bitmap)) {
+ /* Reached non-BMP range which is assumed continuous. */
+ return end;
+ }
+ DUK_ASSERT(offset < sizeof(duk_unicode_re_canon_bitmap));
+ if ((duk_unicode_re_canon_bitmap[offset] & mask) == 0) {
+ /* Block is discontinuous, continuity is guaranteed
+ * only up to end of previous block (+1 for exclusive
+ * return value => start of current block). Start
+ * block requires special handling.
+ */
+ if (blk > start_blk) {
+ return (duk_codepoint_t) (blk << DUK_CANON_BITMAP_BLKSHIFT);
+ } else {
+ return start;
+ }
+ }
+ }
+ DUK_ASSERT(blk == end_blk + 1); /* Reached end block which is continuous. */
+ return end;
+}
+#else /* DUK_USE_REGEXP_CANON_BITMAP */
+DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
+ DUK_ASSERT(start >= 0);
+ DUK_ASSERT(end >= 0);
+ DUK_ASSERT(end >= start);
+ if (start >= 0x10000) {
+ /* Even without the bitmap, treat non-BMP as continuous. */
+ return end;
+ }
+ return start;
+}
+#endif /* DUK_USE_REGEXP_CANON_BITMAP */
-DUK_LOCAL void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
+DUK_LOCAL void duk__regexp_generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
+ duk_codepoint_t r_start;
+ duk_codepoint_t r_end;
+ duk_codepoint_t i;
+ duk_codepoint_t t;
+ duk_codepoint_t r_disc;
- DUK_DD(DUK_DDPRINT("duk__generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
+ DUK_DD(DUK_DDPRINT("duk__regexp_generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
(void *) re_ctx, (long) r1, (long) r2, (long) direct));
- if (!direct && (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE)) {
- /*
- * Canonicalize a range, generating result ranges as necessary.
- * Needs to exhaustively scan the entire range (at most 65536
- * code points). If 'direct' is set, caller (lexer) has ensured
- * that the range is already canonicalization compatible (this
- * is used to avoid unnecessary canonicalization of built-in
- * ranges like \W, which are not affected by canonicalization).
- *
- * NOTE: here is one place where we don't want to support chars
- * outside the BMP, because the exhaustive search would be
- * massively larger.
+ DUK_ASSERT(r2 >= r1); /* SyntaxError for out of order range. */
+
+ if (direct || (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) == 0) {
+ DUK_DD(DUK_DDPRINT("direct or not case sensitive, emit range: [%ld,%ld]", (long) r1, (long) r2));
+ duk__regexp_emit_range(re_ctx, r1, r2);
+ return;
+ }
+
+ DUK_DD(DUK_DDPRINT("case sensitive, process range: [%ld,%ld]", (long) r1, (long) r2));
+
+ r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
+ r_end = r_start;
+
+ for (i = r1 + 1; i <= r2;) {
+ /* Input codepoint space processed up to i-1, and
+ * current range in r_{start,end} is up-to-date
+ * (inclusive) and may either break or continue.
*/
+ r_disc = duk__re_canon_next_discontinuity(i, r2);
+ DUK_ASSERT(r_disc >= i);
+ DUK_ASSERT(r_disc <= r2);
- duk_codepoint_t i;
- duk_codepoint_t t;
- duk_codepoint_t r_start, r_end;
+ r_end += r_disc - i; /* May be zero. */
+ t = duk_unicode_re_canonicalize_char(re_ctx->thr, r_disc);
+ if (t == r_end + 1) {
+ /* Not actually a discontinuity, continue range
+ * to r_disc and recheck.
+ */
+ r_end = t;
+ } else {
+ duk__regexp_emit_range(re_ctx, r_start, r_end);
+ r_start = t;
+ r_end = t;
+ }
+ i = r_disc + 1; /* Guarantees progress. */
+ }
+ duk__regexp_emit_range(re_ctx, r_start, r_end);
- r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
- r_end = r_start;
- for (i = r1 + 1; i <= r2; i++) {
- t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
- if (t == r_end + 1) {
- r_end = t;
- } else {
- DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
- duk__append_u32(re_ctx, (duk_uint32_t) r_start);
- duk__append_u32(re_ctx, (duk_uint32_t) r_end);
- re_ctx->nranges++;
- r_start = t;
- r_end = t;
- }
- }
- DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
- duk__append_u32(re_ctx, (duk_uint32_t) r_start);
- duk__append_u32(re_ctx, (duk_uint32_t) r_end);
- re_ctx->nranges++;
- } else {
- DUK_DD(DUK_DDPRINT("direct, emit range: [%ld,%ld]", (long) r1, (long) r2));
- duk__append_u32(re_ctx, (duk_uint32_t) r1);
- duk__append_u32(re_ctx, (duk_uint32_t) r2);
- re_ctx->nranges++;
+#if 0 /* Exhaustive search, very slow. */
+ r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
+ r_end = r_start;
+ for (i = r1 + 1; i <= r2; i++) {
+ t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
+ if (t == r_end + 1) {
+ r_end = t;
+ } else {
+ DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
+ duk__append_u32(re_ctx, (duk_uint32_t) r_start);
+ duk__append_u32(re_ctx, (duk_uint32_t) r_end);
+ re_ctx->nranges++;
+ r_start = t;
+ r_end = t;
+ }
}
+ DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
+ duk__append_u32(re_ctx, (duk_uint32_t) r_start);
+ duk__append_u32(re_ctx, (duk_uint32_t) r_end);
+ re_ctx->nranges++;
+#endif
}
/*
@@ -83827,21 +85545,21 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
duk_uint32_t offset;
DUK_ASSERT(unpatched_disjunction_split >= 0);
- offset = unpatched_disjunction_jump;
+ offset = (duk_uint32_t) unpatched_disjunction_jump;
offset += duk__insert_jump_offset(re_ctx,
offset,
(duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
/* offset is now target of the pending split (right after jump) */
duk__insert_jump_offset(re_ctx,
- unpatched_disjunction_split,
- offset - unpatched_disjunction_split);
+ (duk_uint32_t) unpatched_disjunction_split,
+ (duk_int32_t) offset - unpatched_disjunction_split);
}
/* add a new pending split to the beginning of the entire disjunction */
(void) duk__insert_u32(re_ctx,
entry_offset,
DUK_REOP_SPLIT1); /* prefer direct execution */
- unpatched_disjunction_split = entry_offset + 1; /* +1 for opcode */
+ unpatched_disjunction_split = (duk_int32_t) (entry_offset + 1); /* +1 for opcode */
/* add a new pending match jump for latest finished alternative */
duk__append_reop(re_ctx, DUK_REOP_JUMP);
@@ -83888,14 +85606,14 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
}
duk__append_reop(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
- atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - atom_start_offset);
+ atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (duk_size_t) atom_start_offset);
- offset = atom_start_offset;
+ offset = (duk_uint32_t) atom_start_offset;
if (re_ctx->curr_token.greedy) {
offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
offset += duk__insert_u32(re_ctx, offset, qmin);
offset += duk__insert_u32(re_ctx, offset, qmax);
- offset += duk__insert_u32(re_ctx, offset, atom_char_length);
+ offset += duk__insert_u32(re_ctx, offset, (duk_uint32_t) atom_char_length);
offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
} else {
offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
@@ -83935,9 +85653,9 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
(long) atom_start_captures, (long) re_ctx->captures));
/* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
- duk__insert_u32(re_ctx, atom_start_offset, (re_ctx->captures - atom_start_captures) * 2);
- duk__insert_u32(re_ctx, atom_start_offset, (atom_start_captures + 1) * 2);
- duk__insert_u32(re_ctx, atom_start_offset, DUK_REOP_WIPERANGE);
+ duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (re_ctx->captures - atom_start_captures) * 2U);
+ duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (atom_start_captures + 1) * 2);
+ duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, DUK_REOP_WIPERANGE);
} else {
DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
(long) atom_start_captures));
@@ -83949,7 +85667,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
tmp_qmin = re_ctx->curr_token.qmin;
tmp_qmax = re_ctx->curr_token.qmax;
while (tmp_qmin > 0) {
- duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
+ duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
tmp_qmin--;
if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
tmp_qmax--;
@@ -83967,7 +85685,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
*/
duk__append_reop(re_ctx, DUK_REOP_JUMP);
duk__append_jump_offset(re_ctx, atom_code_length);
- duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
+ duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
}
if (re_ctx->curr_token.greedy) {
duk__append_reop(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
@@ -83994,7 +85712,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
*/
duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
while (tmp_qmax > 0) {
- duk__insert_slice(re_ctx, offset, atom_start_offset, atom_code_length);
+ duk__insert_slice(re_ctx, offset, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
if (re_ctx->curr_token.greedy) {
duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */
} else {
@@ -84008,7 +85726,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
}
/* remove the original 'template' atom */
- duk__remove_slice(re_ctx, atom_start_offset, atom_code_length);
+ duk__remove_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
}
/* 'taint' result as complex */
@@ -84076,7 +85794,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
duk__append_reop(re_ctx, DUK_REOP_CHAR);
ch = re_ctx->curr_token.num;
if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
- ch = duk_unicode_re_canonicalize_char(re_ctx->thr, ch);
+ ch = (duk_uint32_t) duk_unicode_re_canonicalize_char(re_ctx->thr, (duk_codepoint_t) ch);
}
duk__append_u32(re_ctx, ch);
break;
@@ -84103,8 +85821,8 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
DUK_ASSERT(DUK_RETOK_ATOM_WHITE == DUK_RETOK_ATOM_DIGIT + 2);
DUK_ASSERT(DUK_RETOK_ATOM_WORD_CHAR == DUK_RETOK_ATOM_DIGIT + 4);
- idx = (re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1;
- DUK_ASSERT(idx <= 2); /* Assume continuous token numbers; also checks negative underflow. */
+ idx = (duk_small_uint_t) ((re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1U);
+ DUK_ASSERT(idx <= 2U); /* Assume continuous token numbers; also checks negative underflow. */
duk__append_range_atom_matcher(re_ctx, re_op, duk__re_range_lookup1[idx], duk__re_range_lookup2[idx]);
break;
@@ -84179,7 +85897,7 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
/* parse ranges until character class ends */
re_ctx->nranges = 0; /* note: ctx-wide temporary */
- duk_lexer_parse_re_ranges(&re_ctx->lex, duk__generate_ranges, (void *) re_ctx);
+ duk_lexer_parse_re_ranges(&re_ctx->lex, duk__regexp_generate_ranges, (void *) re_ctx);
/* insert range count */
duk__insert_u32(re_ctx, offset, re_ctx->nranges);
@@ -84225,14 +85943,14 @@ DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t ex
duk_uint32_t offset;
DUK_ASSERT(unpatched_disjunction_split >= 0);
- offset = unpatched_disjunction_jump;
+ offset = (duk_uint32_t) unpatched_disjunction_jump;
offset += duk__insert_jump_offset(re_ctx,
offset,
(duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
/* offset is now target of the pending split (right after jump) */
duk__insert_jump_offset(re_ctx,
- unpatched_disjunction_split,
- offset - unpatched_disjunction_split);
+ (duk_uint32_t) unpatched_disjunction_split,
+ (duk_int32_t) offset - unpatched_disjunction_split);
}
#if 0
@@ -84317,7 +86035,6 @@ DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h)
*/
DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
- duk_context *ctx = (duk_context *) thr;
duk_hstring *h;
const duk_uint8_t *p;
duk_bufwriter_ctx bw_alloc;
@@ -84326,12 +86043,12 @@ DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
duk_size_t i, n;
duk_uint_fast8_t c_prev, c;
- h = duk_known_hstring(ctx, idx_pattern);
+ h = duk_known_hstring(thr, idx_pattern);
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
if (n == 0) {
- duk_push_string(ctx, "(?:)");
+ duk_push_string(thr, "(?:)");
return;
}
@@ -84358,7 +86075,7 @@ DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
}
DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
- (void) duk_buffer_to_string(ctx, -1); /* Safe if input is safe. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe if input is safe. */
/* [ ... escaped_source ] */
}
@@ -84379,7 +86096,6 @@ DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
*/
DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_re_compiler_ctx re_ctx;
duk_lexer_point lex_point;
duk_hstring *h_pattern;
@@ -84387,15 +86103,14 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
duk__re_disjunction_info ign_disj;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
/*
* Args validation
*/
/* TypeError if fails */
- h_pattern = duk_require_hstring_notsymbol(ctx, -2);
- h_flags = duk_require_hstring_notsymbol(ctx, -1);
+ h_pattern = duk_require_hstring_notsymbol(thr, -2);
+ h_flags = duk_require_hstring_notsymbol(thr, -1);
/*
* Create normalized 'source' property (E5 Section 15.10.3).
@@ -84473,7 +86188,7 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
/* [ ... pattern flags escaped_source buffer ] */
DUK_BW_COMPACT(thr, &re_ctx.bw);
- (void) duk_buffer_to_string(ctx, -1); /* Safe because flags is at most 7 bit. */
+ (void) duk_buffer_to_string(thr, -1); /* Safe because flags is at most 7 bit. */
/* [ ... pattern flags escaped_source bytecode ] */
@@ -84481,11 +86196,11 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
* Finalize stack
*/
- duk_remove(ctx, -4); /* -> [ ... flags escaped_source bytecode ] */
- duk_remove(ctx, -3); /* -> [ ... escaped_source bytecode ] */
+ duk_remove(thr, -4); /* -> [ ... flags escaped_source bytecode ] */
+ duk_remove(thr, -3); /* -> [ ... escaped_source bytecode ] */
DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
- (duk_tval *) duk_get_tval(ctx, -1), (duk_tval *) duk_get_tval(ctx, -2)));
+ (duk_tval *) duk_get_tval(thr, -1), (duk_tval *) duk_get_tval(thr, -2)));
}
/*
@@ -84499,21 +86214,20 @@ DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
*/
DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
duk_hobject *h;
/* [ ... escaped_source bytecode ] */
- duk_push_object(ctx);
- h = duk_known_hobject(ctx, -1);
- duk_insert(ctx, -3);
+ duk_push_object(thr);
+ h = duk_known_hobject(thr, -1);
+ duk_insert(thr, -3);
/* [ ... regexp_object escaped_source bytecode ] */
DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
- duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
/* [ ... regexp_object escaped_source ] */
@@ -84522,12 +86236,12 @@ DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
* property for the getter.
*/
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
/* [ ... regexp_object ] */
- duk_push_int(ctx, 0);
- duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
+ duk_push_int(thr, 0);
+ duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
/* [ ... regexp_object ] */
}
@@ -85040,8 +86754,8 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
}
DUK_ASSERT(idx_count > 0);
- duk_require_stack((duk_context *) re_ctx->thr, 1);
- range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero((duk_context *) re_ctx->thr,
+ duk_require_stack(re_ctx->thr, 1);
+ range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
sizeof(duk_uint8_t *) * idx_count);
DUK_ASSERT(range_save != NULL);
DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
@@ -85060,7 +86774,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
(long) idx_start, (long) (idx_start + idx_count - 1),
(long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
sp = sub_sp;
goto match;
}
@@ -85072,7 +86786,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_MEMCPY((void *) (re_ctx->saved + idx_start),
(const void *) range_save,
sizeof(duk_uint8_t *) * idx_count);
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
goto fail;
}
case DUK_REOP_LOOKPOS:
@@ -85087,7 +86801,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
* The temporary save buffer is pushed on to the valstack to handle
* errors correctly. Each lookahead causes a C recursion and pushes
* more stuff on the value stack. If the C recursion limit is less
- * than the value stack spare, there is no need to check the stack.
+ * than the value stack slack, there is no need to check the stack.
* We do so regardless, just in case.
*/
@@ -85097,8 +86811,8 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_ASSERT(re_ctx->nsaved > 0);
- duk_require_stack((duk_context *) re_ctx->thr, 1);
- full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero((duk_context *) re_ctx->thr,
+ duk_require_stack(re_ctx->thr, 1);
+ full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
sizeof(duk_uint8_t *) * re_ctx->nsaved);
DUK_ASSERT(full_save != NULL);
DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
@@ -85117,7 +86831,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
if (sub_sp) {
/* match: keep saves */
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
sp = sub_sp;
goto match;
}
@@ -85129,7 +86843,7 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
DUK_MEMCPY((void *) re_ctx->saved,
(const void *) full_save,
sizeof(duk_uint8_t *) * re_ctx->nsaved);
- duk_pop((duk_context *) re_ctx->thr);
+ duk_pop_unsafe(re_ctx->thr);
goto fail;
}
case DUK_REOP_BACKREFERENCE: {
@@ -85224,7 +86938,6 @@ DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const
*/
DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
- duk_context *ctx = (duk_context *) thr;
duk_re_matcher_ctx re_ctx;
duk_hobject *h_regexp;
duk_hstring *h_bytecode;
@@ -85239,11 +86952,10 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
duk_uint32_t char_offset;
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
+ (duk_tval *) duk_get_tval(thr, -2),
+ (duk_tval *) duk_get_tval(thr, -1)));
/*
* Regexp instance check, bytecode check, input coercion.
@@ -85252,16 +86964,16 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
*/
/* TypeError if wrong; class check, see E5 Section 15.10.6 */
- h_regexp = duk_require_hobject_with_class(ctx, -2, DUK_HOBJECT_CLASS_REGEXP);
+ h_regexp = duk_require_hobject_with_class(thr, -2, DUK_HOBJECT_CLASS_REGEXP);
DUK_ASSERT(h_regexp != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
DUK_UNREF(h_regexp);
- h_input = duk_to_hstring(ctx, -1);
+ h_input = duk_to_hstring(thr, -1);
DUK_ASSERT(h_input != NULL);
- duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
- h_bytecode = duk_require_hstring(ctx, -1); /* no regexp instance should exist without a non-configurable bytecode property */
+ duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
+ h_bytecode = duk_require_hstring(thr, -1); /* no regexp instance should exist without a non-configurable bytecode property */
DUK_ASSERT(h_bytecode != NULL);
/*
@@ -85294,14 +87006,14 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
re_ctx.bytecode = pc;
DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */
- global = (duk_small_int_t) (force_global | (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
+ global = (duk_small_int_t) (force_global | (duk_small_int_t) (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
DUK_ASSERT(re_ctx.nsaved >= 2);
DUK_ASSERT((re_ctx.nsaved % 2) == 0);
- p_buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved); /* rely on zeroing */
+ p_buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, sizeof(duk_uint8_t *) * re_ctx.nsaved); /* rely on zeroing */
DUK_UNREF(p_buf);
- re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
+ re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(thr, -1, NULL);
DUK_ASSERT(re_ctx.saved != NULL);
/* [ ... re_obj input bc saved_buf ] */
@@ -85339,10 +87051,10 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
/* [ ... re_obj input bc saved_buf ] */
- duk_get_prop_stridx_short(ctx, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
- (void) duk_to_int(ctx, -1); /* ToInteger(lastIndex) */
- d = duk_get_number(ctx, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
- duk_pop(ctx);
+ duk_get_prop_stridx_short(thr, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
+ (void) duk_to_int(thr, -1); /* ToInteger(lastIndex) */
+ d = duk_get_number(thr, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
+ duk_pop_nodecref_unsafe(thr);
if (global) {
if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
@@ -85379,7 +87091,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
DUK_ASSERT_DISABLE(char_offset >= 0);
DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
- /* Note: ctx.steps is intentionally not reset, it applies to the entire unanchored match */
+ /* Note: re_ctx.steps is intentionally not reset, it applies to the entire unanchored match */
DUK_ASSERT(re_ctx.recursion_depth == 0);
DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
@@ -85394,7 +87106,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
*
* - Clearing saved[] is not necessary because backtracking does it
*
- * - Backtracking also rewinds ctx.recursion back to zero, unless an
+ * - Backtracking also rewinds re_ctx.recursion back to zero, unless an
* internal/limit error occurs (which causes a longjmp())
*
* - If we supported anchored matches, we would break out here
@@ -85465,10 +87177,10 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
* objects are usually short lived.
*/
- duk_push_array(ctx);
+ duk_push_array(thr);
#if defined(DUK_USE_ASSERTIONS)
- h_res = duk_require_hobject(ctx, -1);
+ h_res = duk_require_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
@@ -85476,11 +87188,11 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
/* [ ... re_obj input bc saved_buf res_obj ] */
- duk_push_u32(ctx, char_offset);
- duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INDEX);
+ duk_push_u32(thr, char_offset);
+ duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INDEX);
- duk_dup_m4(ctx);
- duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INPUT);
+ duk_dup_m4(thr);
+ duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INPUT);
for (i = 0; i < re_ctx.nsaved; i += 2) {
/* Captures which are undefined have NULL pointers and are returned
@@ -85488,7 +87200,7 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
* (this should, of course, never happen in practice).
*/
if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) {
- duk_push_lstring(ctx,
+ duk_push_lstring(thr,
(const char *) re_ctx.saved[i],
(duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
if (i == 0) {
@@ -85497,14 +87209,14 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
* will be zero). Also assumes clen reflects the
* correct char length.
*/
- char_end_offset = char_offset + (duk_uint32_t) duk_get_length(ctx, -1); /* add charlen */
+ char_end_offset = char_offset + (duk_uint32_t) duk_get_length(thr, -1); /* add charlen */
}
} else {
- duk_push_undefined(ctx);
+ duk_push_undefined(thr);
}
/* [ ... re_obj input bc saved_buf res_obj val ] */
- duk_put_prop_index(ctx, -2, i / 2);
+ duk_put_prop_index(thr, -2, (duk_uarridx_t) (i / 2));
}
/* [ ... re_obj input bc saved_buf res_obj ] */
@@ -85513,8 +87225,8 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
if (global) {
/* global regexp: lastIndex updated on match */
- duk_push_u32(ctx, char_end_offset);
- duk_put_prop_stridx_short(ctx, -6, DUK_STRIDX_LAST_INDEX);
+ duk_push_u32(thr, char_end_offset);
+ duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
} else {
/* non-global regexp: lastIndex never updated on match */
;
@@ -85528,21 +87240,21 @@ DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_
DUK_DDD(DUK_DDDPRINT("regexp does not match"));
- duk_push_null(ctx);
+ duk_push_null(thr);
/* [ ... re_obj input bc saved_buf res_obj ] */
- duk_push_int(ctx, 0);
- duk_put_prop_stridx_short(ctx, -6, DUK_STRIDX_LAST_INDEX);
+ duk_push_int(thr, 0);
+ duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
}
/* [ ... re_obj input bc saved_buf res_obj ] */
- duk_insert(ctx, -5);
+ duk_insert(thr, -5);
/* [ ... res_obj re_obj input bc saved_buf ] */
- duk_pop_n(ctx, 4);
+ duk_pop_n_unsafe(thr, 4);
/* [ ... res_obj ] */
@@ -85953,6 +87665,7 @@ DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) {
DUK_LOCAL duk_uint_t duk__selftest_fmod(void) {
duk_uint_t error_count = 0;
duk__test_double_union u1, u2;
+ volatile duk_double_t t1, t2, t3;
/* fmod() with integer argument and exponent 2^32 is used by e.g.
* ToUint32() and some Duktape internals.
@@ -85969,6 +87682,22 @@ DUK_LOCAL duk_uint_t duk__selftest_fmod(void) {
u2.d = 10.0;
DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+ /* 52-bit integer split into two parts:
+ * >>> 0x1fedcba9876543
+ * 8987183256397123
+ * >>> float(0x1fedcba9876543) / float(2**53)
+ * 0.9977777777777778
+ */
+ u1.d = DUK_FMOD(8987183256397123.0, 4294967296.0);
+ u2.d = (duk_double_t) 0xa9876543UL;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+ t1 = 8987183256397123.0;
+ t2 = 4294967296.0;
+ t3 = t1 / t2;
+ u1.d = DUK_FLOOR(t3);
+ u2.d = (duk_double_t) 0x1fedcbUL;
+ DUK__DBLUNION_CMP_TRUE(&u1, &u2);
+
/* C99 behavior is for fmod() result sign to mathc argument sign. */
u1.d = DUK_FMOD(-10.0, 4294967296.0);
u2.d = -10.0;
@@ -86027,7 +87756,7 @@ DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) {
/* Catch a double-to-int64 cast issue encountered in practice. */
d = 2147483648.0;
i = (duk_int64_t) d;
- if (i != 0x80000000LL) {
+ if (i != DUK_I64_CONSTANT(0x80000000)) {
DUK__FAILED("casting 2147483648.0 to duk_int64_t failed");
}
#else
@@ -86122,7 +87851,7 @@ DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func,
}
for (i = 1; i <= 256; i++) {
- ptr = alloc_func(udata, i);
+ ptr = alloc_func(udata, (duk_size_t) i);
if (ptr == NULL) {
DUK_D(DUK_DPRINT("alloc failed, ignore"));
continue; /* alloc failed, ignore */
@@ -86231,9 +87960,9 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *t
if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
duk_int64_t t;
- if (((0x000fffffffffffffLL >> shift) & i) == 0) {
- t = i | 0x0010000000000000LL; /* implicit leading one */
- t = t & 0x001fffffffffffffLL;
+ if (((DUK_I64_CONSTANT(0x000fffffffffffff) >> shift) & i) == 0) {
+ t = i | DUK_I64_CONSTANT(0x0010000000000000); /* implicit leading one */
+ t = t & DUK_I64_CONSTANT(0x001fffffffffffff);
t = t >> (52 - shift);
if (i < 0) {
t = -t;
@@ -86242,13 +87971,13 @@ DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *t
return;
}
} else if (shift == -1023) { /* exponent 0 */
- if (i >= 0 && (i & 0x000fffffffffffffLL) == 0) {
+ if (i >= 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
/* Note: reject negative zero. */
DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
return;
}
} else if (shift == 47) { /* exponent 1070 */
- if (i < 0 && (i & 0x000fffffffffffffLL) == 0) {
+ if (i < 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
return;
}
@@ -86274,15 +88003,15 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval
t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
if ((t >> 48) != DUK_TAG_FASTINT) {
return tv->d;
- } else if (t & 0x0000800000000000ULL) {
+ } else if (t & DUK_U64_CONSTANT(0x0000800000000000)) {
t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
- t = t & 0x0000ffffffffffffULL; /* negative */
- t |= 0xc330000000000000ULL;
+ t = t & DUK_U64_CONSTANT(0x0000ffffffffffff); /* negative */
+ t |= DUK_U64_CONSTANT(0xc330000000000000);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d + 4503599627370496.0; /* 1 << 52 */
} else if (t != 0) {
- t &= 0x0000ffffffffffffULL; /* positive */
- t |= 0x4330000000000000ULL;
+ t &= DUK_U64_CONSTANT(0x0000ffffffffffff); /* positive */
+ t |= DUK_U64_CONSTANT(0x4330000000000000);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d - 4503599627370496.0; /* 1 << 52 */
} else {
@@ -86301,11 +88030,11 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tva
if (tv->t == DUK_TAG_FASTINT) {
if (tv->v.fi >= 0) {
- t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
+ t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d - 4503599627370496.0; /* 1 << 52 */
} else {
- t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
+ t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d + 4503599627370496.0; /* 1 << 52 */
}
@@ -86324,11 +88053,11 @@ DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint
DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
if (tv->v.fi >= 0) {
- t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
+ t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d - 4503599627370496.0; /* 1 << 52 */
} else {
- t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
+ t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
DUK_DBLUNION_SET_UINT64(&du, t);
return du.d + 4503599627370496.0; /* 1 << 52 */
}
@@ -92477,6 +94206,29 @@ const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
65528L,65529L,65530L,65531L,65532L,65533L,65534L,65535L,
};
#endif
+
+#if defined(DUK_USE_REGEXP_CANON_BITMAP)
+/*
+ * Automatically generated by extract_caseconv.py, do not edit!
+ */
+
+const duk_uint8_t duk_unicode_re_canon_bitmap[256] = {
+23,0,224,19,1,228,255,255,255,255,255,255,255,255,255,255,255,255,255,127,
+255,255,255,255,255,255,255,255,231,247,0,16,255,227,255,255,63,255,255,
+255,255,255,255,255,1,252,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+227,193,255,255,255,147,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,251,
+};
+#endif
/*
* Bitstream decoder.
*/
@@ -92520,7 +94272,7 @@ DUK_INTERNAL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t
* to be cleared, we just ignore them on next round.
*/
shift = ctx->currbits - bits;
- mask = (1 << bits) - 1;
+ mask = (((duk_uint32_t) 1U) << bits) - 1U;
tmp = (ctx->currval >> shift) & mask;
ctx->currbits = shift; /* remaining */
@@ -92592,7 +94344,7 @@ DUK_LOCAL const duk_uint8_t duk__bitpacked_lookup[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_UNDERSCORE, DUK_ASC_SPACE,
- 0xff, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY
+ 0x82, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY
};
DUK_INTERNAL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out) {
@@ -92687,7 +94439,7 @@ DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
DUK_ASSERT(ctx->currbits == 0);
}
/*
- * Fast buffer writer with spare management.
+ * Fast buffer writer with slack management.
*/
/* #include duk_internal.h -> already included */
@@ -92715,21 +94467,17 @@ DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_h
DUK_ASSERT(thr != NULL);
DUK_ASSERT(bw_ctx != NULL);
DUK_ASSERT(h_buf != NULL);
- DUK_UNREF(thr);
bw_ctx->buf = h_buf;
duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
}
DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
- duk_context *ctx;
-
DUK_ASSERT(thr != NULL);
DUK_ASSERT(bw_ctx != NULL);
- ctx = (duk_context *) thr;
- (void) duk_push_dynamic_buffer(ctx, buf_size);
- bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, -1);
+ (void) duk_push_dynamic_buffer(thr, buf_size);
+ bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
}
@@ -92749,7 +94497,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_
*/
curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
- add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD;
+ add_sz = (curr_off >> DUK_BW_SLACK_SHIFT) + DUK_BW_SLACK_ADD;
new_sz = curr_off + sz + add_sz;
if (DUK_UNLIKELY(new_sz < curr_off)) {
/* overflow */
@@ -92809,7 +94557,6 @@ DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx
DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
DUK_BW_ENSURE(thr, bw, len);
duk_bw_write_raw_slice(thr, bw, src_off, len);
@@ -92826,7 +94573,7 @@ DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *b
DUK_UNREF(thr);
p_base = bw->p_base;
- buf_sz = bw->p - p_base;
+ buf_sz = (duk_size_t) (bw->p - p_base); /* constrained by maximum buffer size */
move_sz = buf_sz - dst_off;
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
@@ -92844,7 +94591,6 @@ DUK_INTERNAL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx
DUK_ASSERT(bw != NULL);
DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(buf != NULL);
- DUK_UNREF(thr);
DUK_BW_ENSURE(thr, bw, len);
duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
@@ -92874,7 +94620,7 @@ DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *b
src_off += len;
}
- buf_sz = bw->p - p_base;
+ buf_sz = (duk_size_t) (bw->p - p_base);
move_sz = buf_sz - dst_off;
DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
@@ -92894,7 +94640,6 @@ DUK_INTERNAL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx
DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
/* Don't support "straddled" source now. */
DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
@@ -92913,7 +94658,7 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter
DUK_UNREF(thr);
p_base = bw->p_base;
- buf_sz = bw->p - p_base;
+ buf_sz = (duk_size_t) (bw->p - p_base);
move_sz = buf_sz - off;
p_dst = p_base + off + len;
p_src = p_base + off;
@@ -92925,7 +94670,6 @@ DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwri
DUK_ASSERT(thr != NULL);
DUK_ASSERT(bw != NULL);
DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
DUK_BW_ENSURE(thr, bw, len);
return duk_bw_insert_raw_area(thr, bw, off, len);
@@ -93169,9 +94913,9 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
#if defined(DUK__RANDOM_XOROSHIRO128PLUS)
DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_splitmix64(duk_uint64_t *x) {
duk_uint64_t z;
- z = (*x += 0x9E3779B97F4A7C15ULL);
- z = (z ^ (z >> 30U)) * 0xBF58476D1CE4E5B9ULL;
- z = (z ^ (z >> 27U)) * 0x94D049BB133111EBULL;
+ z = (*x += DUK_U64_CONSTANT(0x9E3779B97F4A7C15));
+ z = (z ^ (z >> 30U)) * DUK_U64_CONSTANT(0xBF58476D1CE4E5B9);
+ z = (z ^ (z >> 27U)) * DUK_U64_CONSTANT(0x94D049BB133111EB);
return z ^ (z >> 31U);
}
@@ -93217,7 +94961,7 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
* is the same so a direct assignment works. For mixed endian the
* 32-bit parts must be swapped.
*/
- v = (0x3ffULL << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U);
+ v = (DUK_U64_CONSTANT(0x3ff) << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U);
du.ull[0] = v;
#if defined(DUK_USE_DOUBLE_ME)
do {
@@ -93238,4 +94982,3 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
#undef DUK__RANDOM_XOROSHIRO128PLUS
#undef DUK__RND_BIT
#undef DUK__UPDATE_RND
-#endif
diff --git a/content/handlers/javascript/duktape/duktape.h b/content/handlers/javascript/duktape/duktape.h
index 21257d30c..a3b4f546e 100644
--- a/content/handlers/javascript/duktape/duktape.h
+++ b/content/handlers/javascript/duktape/duktape.h
@@ -1,5 +1,5 @@
/*
- * Duktape public API for Duktape 2.1.0.
+ * Duktape public API for Duktape 2.2.0.
*
* See the API reference for documentation on call semantics. The exposed,
* supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API"
@@ -89,6 +89,9 @@
* * Remko Tron\u00e7on (https://el-tramo.be)
* * Romero Malaquias (rbsm@ic.ufal.br)
* * Michael Drake <michael.drake@codethink.co.uk>
+ * * Steven Don (https://github.com/shdon)
+ * * Simon Stone (https://github.com/sstone1)
+ * * \J. McC. (https://github.com/jmhmccr)
*
* Other contributions
* ===================
@@ -151,7 +154,7 @@
* development snapshots have 99 for patch level (e.g. 0.10.99 would be a
* development version after 0.10.0 but before the next official release).
*/
-#define DUK_VERSION 20100L
+#define DUK_VERSION 20200L
/* Git commit, describe, and branch for Duktape build. Useful for
* non-official snapshot builds so that application code can easily log
@@ -286,35 +289,35 @@ struct duk_time_components {
/* Number of value stack entries (in addition to actual call arguments)
* guaranteed to be allocated on entry to a Duktape/C function.
*/
-#define DUK_API_ENTRY_STACK 64
+#define DUK_API_ENTRY_STACK 64U
/* 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 */
-#define DUK_TYPE_BOOLEAN 3 /* Ecmascript boolean: 0 or 1 */
-#define DUK_TYPE_NUMBER 4 /* Ecmascript number: double */
-#define DUK_TYPE_STRING 5 /* Ecmascript string: CESU-8 / extended UTF-8 encoded */
-#define DUK_TYPE_OBJECT 6 /* Ecmascript object: includes objects, arrays, functions, threads */
-#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
+#define DUK_TYPE_MIN 0U
+#define DUK_TYPE_NONE 0U /* no value, e.g. invalid index */
+#define DUK_TYPE_UNDEFINED 1U /* Ecmascript undefined */
+#define DUK_TYPE_NULL 2U /* Ecmascript null */
+#define DUK_TYPE_BOOLEAN 3U /* Ecmascript boolean: 0 or 1 */
+#define DUK_TYPE_NUMBER 4U /* Ecmascript number: double */
+#define DUK_TYPE_STRING 5U /* Ecmascript string: CESU-8 / extended UTF-8 encoded */
+#define DUK_TYPE_OBJECT 6U /* Ecmascript object: includes objects, arrays, functions, threads */
+#define DUK_TYPE_BUFFER 7U /* fixed or dynamic, garbage collected byte buffer */
+#define DUK_TYPE_POINTER 8U /* raw void pointer */
+#define DUK_TYPE_LIGHTFUNC 9U /* lightweight function pointer */
+#define DUK_TYPE_MAX 9U
/* Value mask types, used by e.g. duk_get_type_mask() */
-#define DUK_TYPE_MASK_NONE (1 << DUK_TYPE_NONE)
-#define DUK_TYPE_MASK_UNDEFINED (1 << DUK_TYPE_UNDEFINED)
-#define DUK_TYPE_MASK_NULL (1 << DUK_TYPE_NULL)
-#define DUK_TYPE_MASK_BOOLEAN (1 << DUK_TYPE_BOOLEAN)
-#define DUK_TYPE_MASK_NUMBER (1 << DUK_TYPE_NUMBER)
-#define DUK_TYPE_MASK_STRING (1 << DUK_TYPE_STRING)
-#define DUK_TYPE_MASK_OBJECT (1 << DUK_TYPE_OBJECT)
-#define DUK_TYPE_MASK_BUFFER (1 << DUK_TYPE_BUFFER)
-#define DUK_TYPE_MASK_POINTER (1 << DUK_TYPE_POINTER)
-#define DUK_TYPE_MASK_LIGHTFUNC (1 << DUK_TYPE_LIGHTFUNC)
-#define DUK_TYPE_MASK_THROW (1 << 10) /* internal flag value: throw if mask doesn't match */
-#define DUK_TYPE_MASK_PROMOTE (1 << 11) /* internal flag value: promote to object if mask matches */
+#define DUK_TYPE_MASK_NONE (1U << DUK_TYPE_NONE)
+#define DUK_TYPE_MASK_UNDEFINED (1U << DUK_TYPE_UNDEFINED)
+#define DUK_TYPE_MASK_NULL (1U << DUK_TYPE_NULL)
+#define DUK_TYPE_MASK_BOOLEAN (1U << DUK_TYPE_BOOLEAN)
+#define DUK_TYPE_MASK_NUMBER (1U << DUK_TYPE_NUMBER)
+#define DUK_TYPE_MASK_STRING (1U << DUK_TYPE_STRING)
+#define DUK_TYPE_MASK_OBJECT (1U << DUK_TYPE_OBJECT)
+#define DUK_TYPE_MASK_BUFFER (1U << DUK_TYPE_BUFFER)
+#define DUK_TYPE_MASK_POINTER (1U << DUK_TYPE_POINTER)
+#define DUK_TYPE_MASK_LIGHTFUNC (1U << DUK_TYPE_LIGHTFUNC)
+#define DUK_TYPE_MASK_THROW (1U << 10) /* internal flag value: throw if mask doesn't match */
+#define DUK_TYPE_MASK_PROMOTE (1U << 11) /* internal flag value: promote to object if mask matches */
/* Coercion hints */
#define DUK_HINT_NONE 0 /* prefer number, unless input is a Date, in which
@@ -324,52 +327,83 @@ struct duk_time_components {
#define DUK_HINT_NUMBER 2 /* prefer number */
/* Enumeration flags for duk_enum() */
-#define DUK_ENUM_INCLUDE_NONENUMERABLE (1 << 0) /* enumerate non-numerable properties in addition to enumerable */
-#define DUK_ENUM_INCLUDE_HIDDEN (1 << 1) /* enumerate hidden symbols too (in Duktape 1.x called internal properties) */
-#define DUK_ENUM_INCLUDE_SYMBOLS (1 << 2) /* enumerate symbols */
-#define DUK_ENUM_EXCLUDE_STRINGS (1 << 3) /* exclude strings */
-#define DUK_ENUM_OWN_PROPERTIES_ONLY (1 << 4) /* don't walk prototype chain, only check own properties */
-#define DUK_ENUM_ARRAY_INDICES_ONLY (1 << 5) /* only enumerate array indices */
-#define DUK_ENUM_SORT_ARRAY_INDICES (1 << 6) /* sort array indices (applied to full enumeration result, including inherited array indices) */
-#define DUK_ENUM_NO_PROXY_BEHAVIOR (1 << 7) /* enumerate a proxy object itself without invoking proxy behavior */
+#define DUK_ENUM_INCLUDE_NONENUMERABLE (1U << 0) /* enumerate non-numerable properties in addition to enumerable */
+#define DUK_ENUM_INCLUDE_HIDDEN (1U << 1) /* enumerate hidden symbols too (in Duktape 1.x called internal properties) */
+#define DUK_ENUM_INCLUDE_SYMBOLS (1U << 2) /* enumerate symbols */
+#define DUK_ENUM_EXCLUDE_STRINGS (1U << 3) /* exclude strings */
+#define DUK_ENUM_OWN_PROPERTIES_ONLY (1U << 4) /* don't walk prototype chain, only check own properties */
+#define DUK_ENUM_ARRAY_INDICES_ONLY (1U << 5) /* only enumerate array indices */
+/* XXX: misleading name */
+#define DUK_ENUM_SORT_ARRAY_INDICES (1U << 6) /* sort array indices (applied to full enumeration result, including inherited array indices); XXX: misleading name */
+#define DUK_ENUM_NO_PROXY_BEHAVIOR (1U << 7) /* enumerate a proxy object itself without invoking proxy behavior */
/* Compilation flags for duk_compile() and duk_eval() */
/* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument.
*/
-#define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */
-#define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */
-#define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */
-#define DUK_COMPILE_SHEBANG (1 << 6) /* allow shebang ('#! ...') comment on first line of source */
-#define DUK_COMPILE_SAFE (1 << 7) /* (internal) catch compilation errors */
-#define DUK_COMPILE_NORESULT (1 << 8) /* (internal) omit eval result */
-#define DUK_COMPILE_NOSOURCE (1 << 9) /* (internal) no source string on stack */
-#define DUK_COMPILE_STRLEN (1 << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */
-#define DUK_COMPILE_NOFILENAME (1 << 11) /* (internal) no filename on stack */
-#define DUK_COMPILE_FUNCEXPR (1 << 12) /* (internal) source is a function expression (used for Function constructor) */
-
-/* Flags for duk_def_prop() and its variants */
-#define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */
-#define DUK_DEFPROP_ENUMERABLE (1 << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */
-#define DUK_DEFPROP_CONFIGURABLE (1 << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */
-#define DUK_DEFPROP_HAVE_WRITABLE (1 << 3) /* set/clear writable */
-#define DUK_DEFPROP_HAVE_ENUMERABLE (1 << 4) /* set/clear enumerable */
-#define DUK_DEFPROP_HAVE_CONFIGURABLE (1 << 5) /* set/clear configurable */
-#define DUK_DEFPROP_HAVE_VALUE (1 << 6) /* set value (given on value stack) */
-#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_COMPILE_EVAL (1U << 3) /* compile eval code (instead of global code) */
+#define DUK_COMPILE_FUNCTION (1U << 4) /* compile function code (instead of global code) */
+#define DUK_COMPILE_STRICT (1U << 5) /* use strict (outer) context for global, eval, or function code */
+#define DUK_COMPILE_SHEBANG (1U << 6) /* allow shebang ('#! ...') comment on first line of source */
+#define DUK_COMPILE_SAFE (1U << 7) /* (internal) catch compilation errors */
+#define DUK_COMPILE_NORESULT (1U << 8) /* (internal) omit eval result */
+#define DUK_COMPILE_NOSOURCE (1U << 9) /* (internal) no source string on stack */
+#define DUK_COMPILE_STRLEN (1U << 10) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */
+#define DUK_COMPILE_NOFILENAME (1U << 11) /* (internal) no filename on stack */
+#define DUK_COMPILE_FUNCEXPR (1U << 12) /* (internal) source is a function expression (used for Function constructor) */
+
+/* Flags for duk_def_prop() and its variants; base flags + a lot of convenience shorthands */
+#define DUK_DEFPROP_WRITABLE (1U << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */
+#define DUK_DEFPROP_ENUMERABLE (1U << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */
+#define DUK_DEFPROP_CONFIGURABLE (1U << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */
+#define DUK_DEFPROP_HAVE_WRITABLE (1U << 3) /* set/clear writable */
+#define DUK_DEFPROP_HAVE_ENUMERABLE (1U << 4) /* set/clear enumerable */
+#define DUK_DEFPROP_HAVE_CONFIGURABLE (1U << 5) /* set/clear configurable */
+#define DUK_DEFPROP_HAVE_VALUE (1U << 6) /* set value (given on value stack) */
+#define DUK_DEFPROP_HAVE_GETTER (1U << 7) /* set getter (given on value stack) */
+#define DUK_DEFPROP_HAVE_SETTER (1U << 8) /* set setter (given on value stack) */
+#define DUK_DEFPROP_FORCE (1U << 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
+#define DUK_DEFPROP_W DUK_DEFPROP_WRITABLE
+#define DUK_DEFPROP_E DUK_DEFPROP_ENUMERABLE
+#define DUK_DEFPROP_C DUK_DEFPROP_CONFIGURABLE
+#define DUK_DEFPROP_WE (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_ENUMERABLE)
+#define DUK_DEFPROP_WC (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_CONFIGURABLE)
+#define DUK_DEFPROP_WEC (DUK_DEFPROP_WRITABLE | DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_CONFIGURABLE)
+#define DUK_DEFPROP_HAVE_W DUK_DEFPROP_HAVE_WRITABLE
+#define DUK_DEFPROP_HAVE_E DUK_DEFPROP_HAVE_ENUMERABLE
+#define DUK_DEFPROP_HAVE_C DUK_DEFPROP_HAVE_CONFIGURABLE
+#define DUK_DEFPROP_HAVE_WE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE)
+#define DUK_DEFPROP_HAVE_WC (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_CONFIGURABLE)
+#define DUK_DEFPROP_HAVE_WEC (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE)
+#define DUK_DEFPROP_SET_W DUK_DEFPROP_SET_WRITABLE
+#define DUK_DEFPROP_SET_E DUK_DEFPROP_SET_ENUMERABLE
+#define DUK_DEFPROP_SET_C DUK_DEFPROP_SET_CONFIGURABLE
+#define DUK_DEFPROP_SET_WE (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_ENUMERABLE)
+#define DUK_DEFPROP_SET_WC (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE)
+#define DUK_DEFPROP_SET_WEC (DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_ENUMERABLE | DUK_DEFPROP_SET_CONFIGURABLE)
+#define DUK_DEFPROP_CLEAR_W DUK_DEFPROP_CLEAR_WRITABLE
+#define DUK_DEFPROP_CLEAR_E DUK_DEFPROP_CLEAR_ENUMERABLE
+#define DUK_DEFPROP_CLEAR_C DUK_DEFPROP_CLEAR_CONFIGURABLE
+#define DUK_DEFPROP_CLEAR_WE (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_ENUMERABLE)
+#define DUK_DEFPROP_CLEAR_WC (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_CONFIGURABLE)
+#define DUK_DEFPROP_CLEAR_WEC (DUK_DEFPROP_CLEAR_WRITABLE | DUK_DEFPROP_CLEAR_ENUMERABLE | DUK_DEFPROP_CLEAR_CONFIGURABLE)
+#define DUK_DEFPROP_ATTR_W (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_W)
+#define DUK_DEFPROP_ATTR_E (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_E)
+#define DUK_DEFPROP_ATTR_C (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_C)
+#define DUK_DEFPROP_ATTR_WE (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WE)
+#define DUK_DEFPROP_ATTR_WC (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WC)
+#define DUK_DEFPROP_ATTR_WEC (DUK_DEFPROP_HAVE_WEC | DUK_DEFPROP_WEC)
/* Flags for duk_push_thread_raw() */
-#define DUK_THREAD_NEW_GLOBAL_ENV (1 << 0) /* create a new global environment */
+#define DUK_THREAD_NEW_GLOBAL_ENV (1U << 0) /* create a new global environment */
/* Flags for duk_gc() */
-#define DUK_GC_COMPACT (1 << 0) /* compact heap objects */
+#define DUK_GC_COMPACT (1U << 0) /* compact heap objects */
/* Error codes (must be 8 bits at most, see duk_error.h) */
#define DUK_ERR_NONE 0 /* no error (e.g. from duk_get_error_code()) */
@@ -400,6 +434,23 @@ struct duk_time_components {
#define DUK_LEVEL_DDDEBUG 2
/*
+ * Macros to create Symbols as C statically constructed strings.
+ *
+ * Call e.g. as DUK_HIDDEN_SYMBOL("myProperty") <=> ("\xFF" "myProperty").
+ * Local symbols have a unique suffix, caller should take care to avoid
+ * conflicting with the Duktape internal representation by e.g. prepending
+ * a '!' character: DUK_LOCAL_SYMBOL("myLocal", "!123").
+ *
+ * Note that these can only be used for string constants, not dynamically
+ * created strings.
+ */
+
+#define DUK_HIDDEN_SYMBOL(x) ("\xFF" x)
+#define DUK_GLOBAL_SYMBOL(x) ("\x80" x)
+#define DUK_LOCAL_SYMBOL(x,uniq) ("\x81" x "\xff" uniq)
+#define DUK_WELLKNOWN_SYMBOL(x) ("\x81" x "\xff")
+
+/*
* If no variadic macros, __FILE__ and __LINE__ are passed through globals
* which is ugly and not thread safe.
*/
@@ -631,6 +682,7 @@ DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx);
DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs);
DUK_EXTERNAL_DECL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic);
DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags);
+DUK_EXTERNAL_DECL duk_idx_t duk_push_proxy(duk_context *ctx, duk_uint_t proxy_flags);
#define duk_push_thread(ctx) \
duk_push_thread_raw((ctx), 0 /*flags*/)
@@ -734,6 +786,8 @@ DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx);
#define duk_is_callable(ctx,idx) \
duk_is_function((ctx), (idx))
+DUK_EXTERNAL_DECL duk_bool_t duk_is_constructable(duk_context *ctx, duk_idx_t idx);
+
DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx);
@@ -850,6 +904,7 @@ DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len);
+DUK_EXTERNAL_DECL void duk_require_object(duk_context *ctx, duk_idx_t idx);
DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size);
DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size);
DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx);
@@ -954,18 +1009,22 @@ DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx);
DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx);
DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx);
DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx);
DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key);
DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len);
DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx);
+DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_heapptr(duk_context *ctx, duk_idx_t obj_idx, void *ptr);
DUK_EXTERNAL_DECL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags);
DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags);
@@ -1024,6 +1083,8 @@ DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx,
DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_idx);
DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags);
DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_idx, duk_bool_t get_value);
+DUK_EXTERNAL_DECL void duk_seal(duk_context *ctx, duk_idx_t obj_idx);
+DUK_EXTERNAL_DECL void duk_freeze(duk_context *ctx, duk_idx_t obj_idx);
/*
* String manipulation