summaryrefslogtreecommitdiff
path: root/javascript/duktape/duktape.c
diff options
context:
space:
mode:
Diffstat (limited to 'javascript/duktape/duktape.c')
-rw-r--r--javascript/duktape/duktape.c2438
1 files changed, 1420 insertions, 1018 deletions
diff --git a/javascript/duktape/duktape.c b/javascript/duktape/duktape.c
index ef221615f..dc62df8d1 100644
--- a/javascript/duktape/duktape.c
+++ b/javascript/duktape/duktape.c
@@ -1,10 +1,8 @@
-/* Omit from static analysis. */
-#ifndef __clang_analyzer__
/*
- * Single source autogenerated distributable for Duktape 1.3.99.
-
- * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f).
- * Git branch duk-config-improvements.
+ * Single source autogenerated distributable for Duktape 1.4.0.
+ *
+ * Git commit cad6f595382a0cc1a7e4207794ade5be11b3e397 (v1.4.0).
+ * Git branch master.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -18,7 +16,7 @@
*
* (http://opensource.org/licenses/MIT)
*
-* Copyright (c) 2013-2015 by Duktape authors (see AUTHORS.rst)
+* Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -68,6 +66,7 @@
* * Legimet <legimet.calc@gmail.com>
* * Karl Skomski <karl@skomski.com>
* * Bruce Pascoe <fatcerberus1@gmail.com>
+* * Ren\u00e9 Hollander <rene@rene8888.at>
*
* Other contributions
* ===================
@@ -104,6 +103,7 @@
* * https://github.com/sstruchtrup
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
+* * Laurent Zubiaur (https://github.com/lzubiaur)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala@iki.fi``) and I'll fix the omission.
@@ -201,6 +201,7 @@ DUK_INTERNAL_DECL int duk_repl_isinf(double x);
#ifndef DUK_JMPBUF_H_INCLUDED
#define DUK_JMPBUF_H_INCLUDED
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
struct duk_jmpbuf {
#if defined(DUK_USE_SETJMP) || defined(DUK_USE_UNDERSCORE_SETJMP)
jmp_buf jb;
@@ -210,8 +211,28 @@ struct duk_jmpbuf {
#error internal error, no long control transfer provider
#endif
};
+#endif
#endif /* DUK_JMPBUF_H_INCLUDED */
+#line 1 "duk_exception.h"
+/*
+ * Exception for Duktape internal throws when C++ exceptions are used
+ * for long control transfers.
+ *
+ * Doesn't inherit from any exception base class to minimize the chance
+ * that user code would accidentally catch this exception.
+ */
+
+#ifndef DUK_EXCEPTION_H_INCLUDED
+#define DUK_EXCEPTION_H_INCLUDED
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+class duk_internal_exception {
+ /* intentionally empty */
+};
+#endif
+
+#endif /* DUK_EXCEPTION_H_INCLUDED */
#line 1 "duk_forwdecl.h"
/*
* Forward declarations for all Duktape structures.
@@ -224,7 +245,11 @@ struct duk_jmpbuf {
* Forward declarations
*/
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+class duk_internal_exception;
+#else
struct duk_jmpbuf;
+#endif
/* duk_tval intentionally skipped */
struct duk_heaphdr;
@@ -275,7 +300,11 @@ struct duk_compiler_ctx;
struct duk_re_matcher_ctx;
struct duk_re_compiler_ctx;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+/* no typedef */
+#else
typedef struct duk_jmpbuf duk_jmpbuf;
+#endif
/* duk_tval intentionally skipped */
typedef struct duk_heaphdr duk_heaphdr;
@@ -1595,13 +1624,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -2940,13 +2969,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -4285,13 +4314,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -4374,7 +4403,7 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#error invalid endianness defines
#endif
#endif /* DUK_BUILTINS_H_INCLUDED */
-#line 50 "duk_internal.h"
+#line 51 "duk_internal.h"
#line 1 "duk_util.h"
/*
@@ -8202,7 +8231,7 @@ DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr
DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
- DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (f); \
+ DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
} while (0)
#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
@@ -10033,7 +10062,9 @@ struct duk_strcache {
*/
struct duk_ljstate {
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
+#endif
duk_small_uint_t type; /* longjmp type */
duk_bool_t iserror; /* isError flag for yield */
duk_tval value1; /* 1st related value (type specific) */
@@ -11272,12 +11303,11 @@ typedef struct {
#define DUK_JS_H_INCLUDED
/* Flags for call handling. */
-#define DUK_CALL_FLAG_PROTECTED (1 << 0) /* duk_handle_call: call is protected */
-#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 1) /* duk_handle_call: call ignores C recursion limit (for errhandler calls) */
-#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 2) /* duk_handle_call: constructor call (i.e. called as 'new Foo()') */
-#define DUK_CALL_FLAG_IS_RESUME (1 << 3) /* duk_handle_ecma_call_setup: setup for a resume() */
-#define DUK_CALL_FLAG_IS_TAILCALL (1 << 4) /* duk_handle_ecma_call_setup: setup for a tail call */
-#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 5) /* call is a direct eval call */
+#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 duk_js_equals_helper(). */
#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
@@ -11354,7 +11384,8 @@ void duk_js_push_closure(duk_hthread *thr,
duk_hobject *outer_lex_env);
/* call handling */
-DUK_INTERNAL_DECL duk_int_t duk_handle_call(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
@@ -11710,7 +11741,7 @@ DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
#endif
#endif /* DUK_SELFTEST_H_INCLUDED */
-#line 77 "duk_internal.h"
+#line 78 "duk_internal.h"
#endif /* DUK_INTERNAL_H_INCLUDED */
#line 1 "duk_strings.c"
@@ -12279,7 +12310,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -12321,50 +12352,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,26,85,197,34,194,175,193,80,26,240,5,149,109,110,236,90,192,
-144,26,208,59,206,126,191,144,139,185,143,218,176,63,160,138,217,81,197,
-125,207,218,144,3,185,73,133,94,242,246,207,218,112,6,11,81,21,62,200,66,
-80,26,80,51,78,223,217,167,168,57,143,218,48,51,78,223,217,167,168,61,143,
-210,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
-80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
-21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
-181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
-3,255,252,81,252,0,0,0,0,8,4,252,68,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,0,0,0,0,0,0,0,32,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,0,0,0,0,0,0,15,3,240,25,127,102,0,1,
-91,127,4,227,0,0,0,0,0,0,3,192,252,6,95,218,128,0,87,31,193,56,192,0,0,0,0,
-0,0,240,63,1,151,246,224,0,21,215,240,78,48,0,0,0,0,0,0,0,16,0,101,253,200,
-0,5,121,252,19,140,0,0,0,0,0,0,0,4,0,25,127,118,0,1,95,127,4,227,0,0,0,0,0,
-0,0,65,0,6,95,222,128,0,88,31,193,56,192,0,0,0,0,0,0,16,64,1,151,247,224,0,
-22,23,240,78,48,0,0,0,0,0,0,4,16,0,101,254,8,0,5,137,252,19,140,0,0,0,0,0,
-0,2,4,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
-248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
-32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
-128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
-0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
-98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
-3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
-128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
-70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
-112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,1,165,92,82,44,42,252,21,1,175,
+0,89,86,214,238,197,172,9,1,173,3,188,231,235,249,8,187,152,253,171,3,250,
+8,173,149,28,87,220,253,169,0,59,148,152,85,239,47,108,253,167,0,96,181,17,
+83,236,132,37,1,165,3,52,237,253,154,122,131,152,253,163,3,52,237,253,154,
+122,131,216,253,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,98,
+146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,0,8,
+99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,64,2,
+152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,0,0,
+191,255,128,0,63,255,197,31,192,0,0,0,0,0,80,196,64,8,26,112,17,169,0,154,
+80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,195,66,
+114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,192,0,31,
+244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,32,0,52,87,
+112,5,89,252,0,1,255,86,16,166,64,0,0,0,0,0,0,2,0,170,72,38,29,219,247,16,
+49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,90,152,62,0,
+6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,250,226,217,
+150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,203,150,254,72,
+52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,224,1,154,140,
+36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,3,104,186,64,
+12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,8,205,2,233,
+0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,33,49,140,
+180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,82,101,16,
+112,24,72,0,8,86,159,193,56,192,0,0,0,0,0,0,240,63,1,151,246,96,0,21,183,
+240,78,48,0,0,0,0,0,0,60,15,192,101,253,168,0,5,113,252,19,140,0,0,0,0,0,0,
+15,3,240,25,127,110,0,1,93,127,4,227,0,0,0,0,0,0,0,1,0,6,95,220,128,0,87,
+159,193,56,192,0,0,0,0,0,0,0,64,1,151,247,96,0,21,247,240,78,48,0,0,0,0,0,
+0,4,16,0,101,253,232,0,5,129,252,19,140,0,0,0,0,0,0,1,4,0,25,127,126,0,1,
+97,127,4,227,0,0,0,0,0,0,0,65,0,6,95,224,128,0,88,159,193,56,192,0,0,0,0,0,
+0,32,64,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,20,10,104,
+79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,0,165,197,
+210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,20,146,23,
+72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,34,52,93,
+32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,160,3,168,
+129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,128,8,160,
+198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,0,52,126,
+25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,136,0,41,
+228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,9,213,118,
+39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -12666,7 +12697,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -12708,50 +12739,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,16,1,111,194,162,197,21,218,90,240,16,0,154,236,110,237,85,
-69,154,208,15,249,139,144,191,190,142,123,218,176,15,253,197,81,217,74,224,
-191,154,144,15,246,242,222,197,73,185,67,154,112,16,2,72,126,213,17,11,70,
-26,80,15,249,168,39,153,159,206,243,90,48,15,253,168,39,153,159,206,243,82,
-104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,80,
-0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,21,
-61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,181,
-250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,3,
-255,252,81,252,4,12,68,248,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,32,0,0,0,0,0,0,0,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,3,255,0,0,0,0,0,0,0,25,127,102,0,1,
-91,127,4,227,0,255,192,0,0,0,0,0,0,6,95,218,128,0,87,31,193,56,192,63,240,
-0,0,0,0,0,0,1,151,246,224,0,21,215,240,78,48,16,0,0,0,0,0,0,0,0,101,253,
-200,0,5,121,252,19,140,4,0,0,0,0,0,0,0,0,25,127,118,0,1,95,127,4,227,1,0,
-64,0,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,64,16,0,0,0,0,0,0,1,151,247,
-224,0,22,23,240,78,48,16,4,0,0,0,0,0,0,0,101,254,8,0,5,137,252,19,140,4,2,
-0,0,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,
-132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,
-92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,
-116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,
-210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,
-136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,
-101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,
-225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,
-2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,
-87,98,112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,1,0,22,252,42,44,81,93,165,175,
+1,0,9,174,198,238,213,84,89,173,0,255,152,185,11,251,232,231,189,171,0,255,
+220,85,29,148,174,11,249,169,0,255,111,45,236,84,155,148,57,167,1,0,36,135,
+237,81,16,180,97,165,0,255,154,130,121,153,252,239,53,163,0,255,218,130,
+121,153,252,239,53,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,
+98,146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,
+0,8,99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,
+64,2,152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,
+0,0,191,255,128,0,63,255,197,31,192,64,196,80,0,0,0,0,0,8,26,112,17,169,0,
+154,80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,
+195,66,114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,
+192,0,31,244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,
+32,0,52,87,112,5,89,252,0,1,255,86,16,166,66,0,0,0,0,0,0,0,0,170,72,38,29,
+219,247,16,49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,
+90,152,62,0,6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,
+250,226,217,150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,
+203,150,254,72,52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,
+224,1,154,140,36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,
+3,104,186,64,12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,
+8,205,2,233,0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,
+33,49,140,180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,
+82,101,16,112,24,72,0,8,86,159,193,56,192,63,240,0,0,0,0,0,0,1,151,246,96,
+0,21,183,240,78,48,15,252,0,0,0,0,0,0,0,101,253,168,0,5,113,252,19,140,3,
+255,0,0,0,0,0,0,0,25,127,110,0,1,93,127,4,227,1,0,0,0,0,0,0,0,0,6,95,220,
+128,0,87,159,193,56,192,64,0,0,0,0,0,0,0,1,151,247,96,0,21,247,240,78,48,
+16,4,0,0,0,0,0,0,0,101,253,232,0,5,129,252,19,140,4,1,0,0,0,0,0,0,0,25,127,
+126,0,1,97,127,4,227,1,0,64,0,0,0,0,0,0,6,95,224,128,0,88,159,193,56,192,
+64,32,0,0,0,0,0,0,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,
+20,10,104,79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,
+0,165,197,210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,
+20,146,23,72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,
+34,52,93,32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,
+160,3,168,129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,
+128,8,160,198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,
+0,52,126,25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,
+136,0,41,228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,
+9,213,118,39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -13053,7 +13084,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -13095,50 +13126,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,2,175,193,80,26,85,197,34,218,240,44,90,192,144,5,149,109,
-110,218,208,16,139,185,143,251,206,126,191,154,176,17,197,125,207,255,160,
-138,217,90,144,30,242,246,207,195,185,73,133,90,112,62,200,66,80,6,11,81,
-21,26,80,39,168,57,143,243,78,223,217,154,48,39,168,61,143,243,78,223,217,
-146,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
-80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
-21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
-181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
-3,255,252,81,252,8,4,252,68,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,0,0,0,32,0,0,0,0,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,0,0,15,3,240,0,0,0,0,25,127,102,0,1,
-91,127,4,227,0,0,3,192,252,0,0,0,0,6,95,218,128,0,87,31,193,56,192,0,0,240,
-63,0,0,0,0,1,151,246,224,0,21,215,240,78,48,0,0,0,16,0,0,0,0,0,101,253,200,
-0,5,121,252,19,140,0,0,0,4,0,0,0,0,0,25,127,118,0,1,95,127,4,227,0,0,0,65,
-0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,0,0,16,64,0,0,0,0,1,151,247,224,
-0,22,23,240,78,48,0,0,4,16,0,0,0,0,0,101,254,8,0,5,137,252,19,140,0,0,2,4,
-0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
-248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
-32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
-128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
-0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
-98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
-3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
-128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
-70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
-112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,0,42,252,21,1,165,92,82,45,175,
+2,197,172,9,0,89,86,214,237,173,1,8,187,152,255,188,231,235,249,171,1,28,
+87,220,255,250,8,173,149,169,1,239,47,108,252,59,148,152,85,167,3,236,132,
+37,0,96,181,17,81,165,2,122,131,152,255,52,237,253,153,163,2,122,131,216,
+255,52,237,253,153,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,
+98,146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,
+0,8,99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,
+64,2,152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,
+0,0,191,255,128,0,63,255,197,31,192,0,80,196,64,0,0,0,0,8,26,112,17,169,0,
+154,80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,
+195,66,114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,
+192,0,31,244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,
+32,0,52,87,112,5,89,252,0,1,255,86,16,166,64,0,0,2,0,0,0,0,0,170,72,38,29,
+219,247,16,49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,
+90,152,62,0,6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,
+250,226,217,150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,
+203,150,254,72,52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,
+224,1,154,140,36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,
+3,104,186,64,12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,
+8,205,2,233,0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,
+33,49,140,180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,
+82,101,16,112,24,72,0,8,86,159,193,56,192,0,0,240,63,0,0,0,0,1,151,246,96,
+0,21,183,240,78,48,0,0,60,15,192,0,0,0,0,101,253,168,0,5,113,252,19,140,0,
+0,15,3,240,0,0,0,0,25,127,110,0,1,93,127,4,227,0,0,0,1,0,0,0,0,0,6,95,220,
+128,0,87,159,193,56,192,0,0,0,64,0,0,0,0,1,151,247,96,0,21,247,240,78,48,0,
+0,4,16,0,0,0,0,0,101,253,232,0,5,129,252,19,140,0,0,1,4,0,0,0,0,0,25,127,
+126,0,1,97,127,4,227,0,0,0,65,0,0,0,0,0,6,95,224,128,0,88,159,193,56,192,0,
+0,32,64,0,0,0,0,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,20,
+10,104,79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,0,
+165,197,210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,
+20,146,23,72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,
+34,52,93,32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,
+160,3,168,129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,
+128,8,160,198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,
+0,52,126,25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,
+136,0,41,228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,
+9,213,118,39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -15778,7 +15809,6 @@ DUK_EXTERNAL void duk_call(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_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(thr != NULL);
@@ -15797,17 +15827,15 @@ DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
call_flags = 0; /* not protected, respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
}
DUK_EXTERNAL void duk_call_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_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(thr != NULL);
@@ -15820,10 +15848,9 @@ DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
call_flags = 0; /* not protected, respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
}
DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
@@ -15872,11 +15899,11 @@ DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
duk_push_undefined(ctx);
duk_insert(ctx, idx_func + 1);
- call_flags = DUK_CALL_FLAG_PROTECTED; /* protected, respect reclimit, not constructor */
+ call_flags = 0; /* respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
return rc;
}
@@ -15897,11 +15924,11 @@ DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
return DUK_EXEC_ERROR; /* unreachable */
}
- call_flags = DUK_CALL_FLAG_PROTECTED; /* protected, respect reclimit, not constructor */
+ call_flags = 0; /* respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
return rc;
}
@@ -16010,7 +16037,6 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
duk_hobject *fallback;
duk_idx_t idx_cons;
duk_small_uint_t call_flags;
- duk_int_t rc;
DUK_ASSERT_CTX_VALID(ctx);
@@ -16104,15 +16130,13 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
/* [... fallback retval] */
- DUK_DDD(DUK_DDDPRINT("constructor call finished, rc=%ld, fallback=%!iT, retval=%!iT",
- (long) rc,
+ 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)));
@@ -20672,16 +20696,16 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
* true
*/
duk_small_uint_t lf_flags;
- duk_small_uint_t nargs;
+ duk_idx_t nargs;
duk_small_uint_t lf_len;
duk_c_function func;
duk_hnativefunction *nf;
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
- nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = DUK_VARARGS;
+ nargs = (duk_idx_t) DUK_VARARGS;
}
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
@@ -20691,10 +20715,10 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
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, (duk_idx_t) nargs, flags);
+ (void) duk__push_c_function_raw(ctx, func, nargs, flags);
lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- if (lf_len != nargs) {
+ if ((duk_idx_t) lf_len != nargs) {
/* Explicit length is only needed if it differs from 'nargs'. */
duk_push_int(ctx, (duk_int_t) lf_len);
duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
@@ -21889,7 +21913,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
duk_hnativefunction *obj;
duk_idx_t ret;
duk_tval *tv_slot;
- duk_uint16_t func_nargs;
+ duk_int16_t func_nargs;
DUK_ASSERT_CTX_VALID(ctx);
@@ -21901,7 +21925,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
goto api_error;
}
if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
- func_nargs = (duk_uint16_t) nargs;
+ func_nargs = (duk_int16_t) nargs;
} else if (nargs == DUK_VARARGS) {
func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
} else {
@@ -25623,8 +25647,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->offset = h_bufarg->offset + byte_offset;
h_bufobj->length = byte_length;
- h_bufobj->shift = shift;
- h_bufobj->elem_type = elem_type;
+ h_bufobj->shift = (duk_uint8_t) shift;
+ h_bufobj->elem_type = (duk_uint8_t) elem_type;
h_bufobj->is_view = 1;
DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
@@ -25727,8 +25751,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_HBUFFER_INCREF(thr, h_val);
DUK_ASSERT(h_bufobj->offset == 0);
h_bufobj->length = byte_length;
- h_bufobj->shift = shift;
- h_bufobj->elem_type = elem_type;
+ h_bufobj->shift = (duk_uint8_t) shift;
+ h_bufobj->elem_type = (duk_uint8_t) elem_type;
h_bufobj->is_view = 1;
DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
@@ -31241,7 +31265,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
duk_small_uint_t comp_flags;
duk_int_t level = -2;
- DUK_ASSERT_TOP(ctx, 1);
+ DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
(thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
@@ -38486,7 +38510,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
thr->heap->lj.iserror = is_error;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
+#endif
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
return 0; /* never here */
@@ -38603,7 +38629,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
thr->heap->lj.iserror = is_error;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
+#endif
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
return 0; /* never here */
@@ -41388,7 +41416,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
/* [ ... eval "eval" eval_input level ] */
- call_flags = DUK_CALL_FLAG_PROTECTED;
+ call_flags = 0;
if (thr->callstack_top >= (duk_size_t) -level) {
duk_activation *act;
duk_hobject *fun;
@@ -41405,7 +41433,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
}
}
- call_ret = duk_handle_call(thr, 2 /*num_stack_args*/, call_flags);
+ call_ret = duk_handle_call_protected(thr, 2 /*num_stack_args*/, call_flags);
if (call_ret == DUK_EXEC_SUCCESS) {
eval_err = 0;
@@ -42151,12 +42179,11 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
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_PROTECTED |
- DUK_CALL_FLAG_IGNORE_RECLIMIT; /* protected, ignore reclimit, not constructor */
+ call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
- rc = duk_handle_call(thr,
- 1, /* num args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr,
+ 1, /* num args */
+ call_flags); /* call_flags */
DUK_UNREF(rc); /* no need to check now: both success and error are OK */
DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
@@ -42591,6 +42618,12 @@ DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ /* XXX: detecting uncaught exception case for C++ case; perhaps need
+ * some marker in heap->lj state that a try-catch is active. For now,
+ * invokes C++ uncaught exception handling.
+ */
+#else
if (!thr->heap->lj.jmpbuf_ptr) {
/*
* If we don't have a jmpbuf_ptr, there is little we can do
@@ -42605,8 +42638,16 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
DUK_UNREACHABLE();
}
+#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ {
+ duk_internal_exception exc; /* dummy */
+ throw exc;
+ }
+#else
DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
+#endif
DUK_UNREACHABLE();
}
#line 1 "duk_error_misc.c"
@@ -43731,7 +43772,9 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
DUK__DUMPSZ(duk_tval);
/* structs from duk_forwdecl.h */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK__DUMPSZ(duk_jmpbuf);
+#endif
DUK__DUMPSZ(duk_heaphdr);
DUK__DUMPSZ(duk_heaphdr_string);
DUK__DUMPSZ(duk_hstring);
@@ -56652,22 +56695,80 @@ DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new
/*
* Call handling.
*
- * The main work horse functions are:
- * - duk_handle_call(): call to a C/Ecmascript functions
- * - duk_handle_safe_call(): make a protected C call within current activation
- * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls, including
- * tail calls and coroutine resume
+ * Main functions are:
+ *
+ * - 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
+ *
+ * See 'execution.rst'.
+ *
+ * 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.
*/
/* include removed: duk_internal.h */
/*
- * Misc
+ * 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
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ );
+DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
+ duk_safe_call_function func,
+ 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
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ );
+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);
+
+/*
+ * Interrupt counter fixup (for development only).
*/
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
- /* XXX: Currently the bytecode executor and executor interrupt
+ /* Currently the bytecode executor and executor interrupt
* instruction counts are off because we don't execute the
* interrupt handler when we're about to exit from the initial
* user call into Duktape.
@@ -56699,18 +56800,17 @@ DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_th
/*
* Arguments object creation.
*
- * Creating arguments objects is a bit finicky, see E5 Section 10.6 for the
- * specific requirements. Much of the arguments object exotic behavior is
- * implemented in duk_hobject_props.c, and is enabled by the object flag
- * DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
+ * Creating arguments objects involves many small details, see E5 Section
+ * 10.6 for the specific requirements. Much of the arguments object exotic
+ * behavior is implemented in duk_hobject_props.c, and is enabled by the
+ * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
*/
-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_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_hobject *arg; /* 'arguments' */
duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
@@ -56789,7 +56889,7 @@ void duk__create_arguments_object(duk_hthread *thr,
-1); /* no prototype */
DUK_ASSERT(i_mappednames >= 0);
- /* [... formals arguments map mappedNames] */
+ /* [ ... formals arguments map mappedNames ] */
DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
"arguments at index %ld -> %!O "
@@ -56831,14 +56931,14 @@ void duk__create_arguments_object(duk_hthread *thr,
duk_get_prop_index(ctx, i_formals, idx);
DUK_ASSERT(duk_is_string(ctx, -1));
- duk_dup(ctx, -1); /* [... name name] */
+ duk_dup(ctx, -1); /* [ ... name name ] */
if (!duk_has_prop(ctx, i_mappednames)) {
/* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
* differs from the reference model
*/
- /* [... name] */
+ /* [ ... name ] */
need_map = 1;
@@ -56859,7 +56959,7 @@ void duk__create_arguments_object(duk_hthread *thr,
/* duk_has_prop() popped the second 'name' */
}
- /* [... name] */
+ /* [ ... name ] */
duk_pop(ctx); /* pop 'name' */
}
@@ -56893,18 +56993,17 @@ void duk__create_arguments_object(duk_hthread *thr,
/* steps 13-14 */
if (DUK_HOBJECT_HAS_STRICT(func)) {
- /*
- * Note: callee/caller are throwers and are not deletable etc.
- * They could be implemented as virtual properties, but currently
- * there is no support for virtual properties which are accessors
- * (only plain virtual properties). This would not be difficult
- * to change in duk_hobject_props, but we can make the throwers
- * normal, concrete properties just as easily.
+ /* Callee/caller are throwers and are not deletable etc. They
+ * could be implemented as virtual properties, but currently
+ * there is no support for virtual properties which are accessors
+ * (only plain virtual properties). This would not be difficult
+ * to change in duk_hobject_props, but we can make the throwers
+ * normal, concrete properties just as easily.
*
- * Note that the specification requires that the *same* thrower
- * built-in object is used here! See E5 Section 10.6 main
- * algoritm, step 14, and Section 13.2.3 which describes the
- * thrower. See test case test-arguments-throwers.js.
+ * Note that the specification requires that the *same* thrower
+ * built-in object is used here! See E5 Section 10.6 main
+ * algoritm, step 14, and Section 13.2.3 which describes the
+ * thrower. See test case test-arguments-throwers.js.
*/
DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
@@ -56919,15 +57018,14 @@ void duk__create_arguments_object(duk_hthread *thr,
/* set exotic behavior only after we're done */
if (need_map) {
- /*
- * Note: exotic behaviors are only enabled for arguments
- * objects which have a parameter map (see E5 Section 10.6
- * main algorithm, step 12).
+ /* Exotic behaviors are only enabled for arguments objects
+ * which have a parameter map (see E5 Section 10.6 main
+ * algorithm, step 12).
*
- * In particular, a non-strict arguments object with no
- * mapped formals does *NOT* get exotic behavior, even
- * for e.g. "caller" property. This seems counterintuitive
- * but seems to be the case.
+ * In particular, a non-strict arguments object with no
+ * mapped formals does *NOT* get exotic behavior, even
+ * for e.g. "caller" property. This seems counterintuitive
+ * but seems to be the case.
*/
/* cannot be strict (never mapped variables) */
@@ -56939,7 +57037,6 @@ void duk__create_arguments_object(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
}
- /* nice log */
DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
"arguments at index %ld -> %!O "
"map at index %ld -> %!O "
@@ -56948,20 +57045,22 @@ void duk__create_arguments_object(duk_hthread *thr,
(long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
(long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
- /* [args(n) [crud] formals arguments map mappednames] -> [args [crud] arguments] */
+ /* [ args(n) [crud] formals arguments map mappednames ] */
+
duk_pop_2(ctx);
duk_remove(ctx, -2);
+
+ /* [ args [crud] 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.
*/
-DUK_LOCAL
-void duk__handle_createargs_for_call(duk_hthread *thr,
- duk_hobject *func,
- duk_hobject *env,
- duk_idx_t num_stack_args) {
+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_DDD(DUK_DDDPRINT("creating arguments object for function call"));
@@ -56972,7 +57071,7 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
duk__create_arguments_object(thr,
func,
@@ -56980,14 +57079,14 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
num_stack_args);
- /* [... arg1 ... argN envobj argobj] */
+ /* [ ... arg1 ... argN envobj argobj ] */
duk_xdef_prop_stridx(ctx,
-2,
DUK_STRIDX_LC_ARGUMENTS,
DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
}
/*
@@ -57004,11 +57103,10 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
* function. This would make call time handling much easier.
*/
-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_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;
@@ -57101,7 +57199,7 @@ void duk__handle_bound_chain_for_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
tv_func = duk_require_tval(ctx, idx_func);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
if (DUK_TVAL_IS_OBJECT(tv_func)) {
@@ -57122,10 +57220,9 @@ void duk__handle_bound_chain_for_call(duk_hthread *thr,
* assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
*/
-DUK_LOCAL
-void duk__handle_oldenv_for_call(duk_hthread *thr,
- duk_hobject *func,
- duk_activation *act) {
+DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
+ duk_hobject *func,
+ duk_activation *act) {
duk_tval *tv;
DUK_ASSERT(thr != NULL);
@@ -57161,7 +57258,7 @@ void duk__handle_oldenv_for_call(duk_hthread *thr,
* Helper for updating callee 'caller' property.
*/
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
duk_tval *tv_caller;
duk_hobject *h_tmp;
@@ -57181,6 +57278,8 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
act_callee = thr->callstack + thr->callstack_top - 1;
act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
+ /* XXX: check .caller writability? */
+
/* Backup 'caller' property and update its value. */
tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
if (tv_caller) {
@@ -57263,10 +57362,9 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* 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_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_tval *tv_this;
duk_hobject *obj_global;
@@ -57316,12 +57414,11 @@ void duk__coerce_effective_this_binding(duk_hthread *thr,
* Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
*/
-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_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;
duk_tval *tv_func;
duk_hobject *func;
@@ -57377,19 +57474,23 @@ duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
}
/*
- * Value stack resize and stack top adjustment helper
+ * Value stack resize and stack top adjustment helper.
*
* XXX: This should all be merged to duk_valstack_resize_raw().
*/
-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_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 */
+ 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);
@@ -57400,15 +57501,17 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
vs_min_size += num_stack_args; /* num entries of new func at entry */
}
if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
+ vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
}
- vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
+ vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
- /* XXX: Awkward fix for GH-107: 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. Ideally duk_valstack_resize_raw() would have
- * a combined algorithm to avoid this.
+ /* 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.
*/
if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
@@ -57436,14 +57539,111 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
}
/*
- * Helper for making various kinds of calls.
- *
- * Call flags:
+ * Manipulate value stack so that exactly 'num_stack_rets' return
+ * values are at 'idx_retbase' in every case, assuming there are
+ * 'rc' return values on top of stack.
*
- * DUK_CALL_FLAG_PROTECTED <--> protected call
- * DUK_CALL_FLAG_IGNORE_RECLIMIT <--> ignore C recursion limit,
- * for errhandler calls
- * DUK_CALL_FLAG_CONSTRUCTOR_CALL <--> for 'new Foo()' calls
+ * This is a bit tricky, because the called C function operates in
+ * the same activation record and may have e.g. popped the stack
+ * empty (below idx_retbase).
+ */
+
+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);
+ DUK_ASSERT(idx_retbase >= 0);
+ 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 */
+
+ 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) 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.
+ */
+ 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) {
+ 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
+ */
+
+ DUK_ASSERT(count >= 0);
+
+ for (i = 0; i < count; i++) {
+ /* XXX: inefficient; block remove primitive */
+ duk_remove(ctx, idx_retbase);
+ }
+ } 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
+ */
+
+ DUK_ASSERT(count > 0);
+
+ for (i = 0; i < count; i++) {
+ /* XXX: inefficient; block insert primitive */
+ duk_push_undefined(ctx);
+ duk_insert(ctx, idx_rcbase);
+ }
+ }
+}
+
+/*
+ * 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_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ return 0;
+ }
+ idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
+ return idx_func;
+}
+
+/*
+ * duk_handle_call_protected() and duk_handle_call_unprotected():
+ * call into a Duktape/C or an Ecmascript function from any state.
*
* Input stack (thr):
*
@@ -57454,34 +57654,19 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
* [ 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.
- * For instance, if we run out of memory when setting up the return stack
- * after a caught error, the out of memory is propagated to the caller.
- * Similarly, API errors (such as invalid input stack shape and invalid
- * indices) cause an error to propagate out of this function. If there is
- * no catchpoint for this error, the fatal error handler is called.
+ * 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.
*
- * See 'execution.rst'.
- *
- * The allowed thread states for making a call are:
- * - thr matches heap->curr_thread, and thr is already RUNNING
- * - thr does not match heap->curr_thread (may be NULL or other),
- * and thr is INACTIVE (in this case, a setjmp() catchpoint is
- * always used for thread book-keeping to work properly)
- *
- * Like elsewhere, gotos are used to keep indent level minimal and
- * avoiding a dozen helpers with awkward plumbing.
- *
- * 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.
+ * 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.)
*/
-DUK_INTERNAL
-duk_int_t duk_handle_call(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_context *ctx = (duk_context *) thr;
+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;
@@ -57490,37 +57675,33 @@ duk_int_t duk_handle_call(duk_hthread *thr,
duk_hthread *entry_curr_thread;
duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
- volatile duk_bool_t need_setjmp;
- duk_jmpbuf * volatile old_jmpbuf_ptr = NULL; /* ptr is volatile (not the target) */
- volatile duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
- duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
- duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
- duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
- 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;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ duk_jmpbuf *old_jmpbuf_ptr = NULL;
duk_jmpbuf our_jmpbuf;
- duk_int_t retval = DUK_EXEC_ERROR;
- duk_ret_t rc;
+#endif
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+
+ /* 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().
+ */
+ ctx = (duk_context *) thr;
+ DUK_UNREF(ctx);
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != 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);
- /*
- * Preliminaries, required by setjmp() handler.
- *
- * Must be careful not to throw an unintended error here.
- *
- * Note: careful with indices like '-x'; if 'x' is zero, it
- * refers to valstack_bottom.
+ /* Argument validation and func/args offset. */
+ idx_func = duk__get_idx_func(thr, num_stack_args);
+
+ /* Preliminaries, required by setjmp() handler. Must be careful not
+ * to throw an unintended error here.
*/
entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
@@ -57537,29 +57718,19 @@ duk_int_t duk_handle_call(duk_hthread *thr,
entry_thread_state = thr->state;
entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
- idx_func = duk_normalize_index(ctx, -num_stack_args - 2); /* idx_func must be valid, note: non-throwing! */
- idx_args = idx_func + 2; /* idx_args is not necessarily valid if num_stack_args == 0 (idx_args then equals top) */
-
- /* Need a setjmp() catchpoint if a protected call OR if we need to
- * do mandatory cleanup.
- */
- need_setjmp = ((call_flags & DUK_CALL_FLAG_PROTECTED) != 0) || (thr->heap->curr_thread != thr);
-
- DUK_DD(DUK_DDPRINT("duk_handle_call: thr=%p, num_stack_args=%ld, "
- "call_flags=0x%08lx (protected=%ld, ignorerec=%ld, constructor=%ld), need_setjmp=%ld, "
+ 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_PROTECTED) != 0 ? 1 : 0),
(long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
(long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
- (long) need_setjmp,
(long) duk_get_top(ctx),
(long) idx_func,
- (long) idx_args,
+ (long) (idx_func + 2),
(long) thr->heap->call_recursion_depth,
(long) thr->heap->call_recursion_limit,
(long) entry_valstack_bottom_index,
@@ -57569,161 +57740,207 @@ duk_int_t duk_handle_call(duk_hthread *thr,
(void *) entry_curr_thread,
(long) entry_thread_state));
- /* 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);
-
- /* 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().
- */
-
- if (idx_func < 0 || idx_args < 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_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- /*
- * Setup a setjmp() catchpoint first because even the call setup
- * may fail.
- */
-
- if (!need_setjmp) {
- DUK_DDD(DUK_DDDPRINT("don't need a setjmp catchpoint"));
- goto handle_call;
- }
-
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
+#endif
- if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
- DUK_DDD(DUK_DDDPRINT("setjmp catchpoint setup complete"));
- goto handle_call;
- }
-
- /*
- * Error during setup, call, or postprocessing of the call.
- * The error value is in heap->lj.value1.
- *
- * Note: any local variables accessed here must have their value
- * assigned *before* the setjmp() call, OR they must be declared
- * volatile. Otherwise their value is not guaranteed to be correct.
- *
- * The following are such variables:
- * - duk_handle_call() parameters
- * - entry_*
- * - idx_func
- * - idx_args
- *
- * The very first thing we do is restore the previous setjmp catcher.
- * This means that any error in error handling will propagate outwards
- * instead of causing a setjmp() re-entry above. The *only* actual
- * errors that should happen here are allocation errors.
- */
-
- DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_call(): %!T",
- (duk_tval *) &thr->heap->lj.value1));
-
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
-
- /* We don't need to sync back thr->curr_pc here because the
- * bytecode executor always has a setjmp catchpoint which
- * does that before errors propagate to here.
- */
-
- /*
- * Restore previous setjmp catchpoint
- */
-
- /* Note: either pointer may be NULL (at entry), so don't assert */
- DUK_DDD(DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p",
- (void *) (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
- (void *) old_jmpbuf_ptr));
-
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- if (!(call_flags & DUK_CALL_FLAG_PROTECTED)) {
- /*
- * Caller did not request a protected call but a setjmp
- * catchpoint was set up to allow cleanup. So, clean up
- * and rethrow.
- *
- * We must restore curr_thread here to ensure that its
- * current value doesn't end up pointing to a thread object
- * which has been freed. This is now a problem because some
- * call sites (namely duk_safe_call()) *first* unwind stacks
- * and only then deal with curr_thread. If those call sites
- * were fixed, this wouldn't matter here.
- *
- * Note: this case happens e.g. when heap->curr_thread is
- * NULL on entry.
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0)) {
+#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_DDD(DUK_DDDPRINT("call is not protected -> clean up and rethrow"));
+ /* Success path handles */
+ DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
+ DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
- /* Restore entry thread executor curr_pc stack frame pointer. */
- thr->ptr_curr_pc = entry_ptr_curr_pc;
+ /* Longjmp state is kept clean in success path */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
- DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
- thr->state = 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 */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- /* XXX: should setjmp catcher be responsible for this instead? */
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- }
+ return DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+#endif
+ /* Error; error value is in heap->lj.value1. */
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+
+ 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
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , old_jmpbuf_ptr
+#endif
+ );
+
+ /* Longjmp state is cleaned up by error handling */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+ return 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(thr, DUK_ERR_API_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__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);
+ return DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "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__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);
+ return DUK_EXEC_ERROR;
+ }
+ }
+#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;
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ 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);
- /* [ ... func this (crud) errobj ] */
+ 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)));
- /* XXX: is there space? better implementation: write directly over
- * 'func' slot to avoid valstack grow issues.
+ /*
+ * Store entry state.
*/
- duk_push_tval(ctx, &thr->heap->lj.value1);
-
- /* [ ... func this (crud) errobj ] */
-
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
- /* [ ... errobj ] */
+ 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;
+#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 */
- /* 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.
+ /* 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);
- (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);
+ 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));
- /* Note: currently a second setjmp restoration is done at the target;
- * this is OK, but could be refactored away.
- */
- retval = DUK_EXEC_ERROR;
- goto shrink_and_finished;
- handle_call:
/*
* Thread state check and book-keeping.
*/
@@ -57748,7 +57965,6 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* state, but not in the same "resume chain".
*/
}
-
DUK_ASSERT(thr->heap->curr_thread == thr);
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
@@ -57758,9 +57974,12 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* possible by recursive handle_call / handle_safe_call calls).
*/
+ /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
+ * reclimit bump?
+ */
+
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 {
@@ -57802,45 +58021,10 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
(duk_tval *) duk_get_tval(ctx, idx_func + 1)));
- /* 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);
-
- if (func == NULL) {
- duk_small_uint_t lf_flags;
-
- DUK_DDD(DUK_DDDPRINT("lightfunc call handling"));
- DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
- 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 */
- }
- nregs = nargs;
- } else if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- nargs = ((duk_hcompiledfunction *) func)->nargs;
- nregs = ((duk_hcompiledfunction *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(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_hnativefunction *) func)->nargs;
- nregs = nargs;
- } else {
- /* XXX: this should be an assert */
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
- }
-
/* [ ... func this arg1 ... argN ] */
/*
- * Setup a preliminary activation.
+ * 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.
@@ -57870,41 +58054,77 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
act->flags = 0;
- if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
- act->flags |= DUK_ACT_FLAG_STRICT;
- }
+
+ /* 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 |= DUK_ACT_FLAG_CONSTRUCT;
- /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
- }
- if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
}
if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
}
- /* As a first approximation, all calls except Ecmascript-to-Ecmascript
- * calls prevent a yield.
+ /* 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.
*/
- act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
+ nargs = 0; DUK_UNREF(nargs);
+ nregs = 0; DUK_UNREF(nregs);
+
+ if (DUK_LIKELY(func != NULL)) {
+ if (DUK_HOBJECT_HAS_STRICT(func)) {
+ act->flags |= DUK_ACT_FLAG_STRICT;
+ }
+ if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
+ nargs = ((duk_hcompiledfunction *) func)->nargs;
+ nregs = ((duk_hcompiledfunction *) func)->nregs;
+ DUK_ASSERT(nregs >= nargs);
+ } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(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_hnativefunction *) func)->nargs;
+ nregs = nargs;
+ } else {
+ /* XXX: this should be an assert */
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
+ }
+ } else {
+ duk_small_uint_t lf_flags;
+
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
+ 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 */
+ }
+ nregs = nargs;
+
+ act->flags |= DUK_ACT_FLAG_STRICT;
+ }
act->func = func; /* NULL for lightfunc */
act->var_env = NULL;
act->lex_env = NULL;
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
act->curr_pc = NULL;
#if defined(DUK_USE_DEBUGGER_SUPPORT)
act->prev_line = 0;
#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_args;
+ 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;
#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?
+ */
if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
/* duk_hthread_callstack_unwind() will decrease this on unwind */
thr->callstack_preventcount++;
@@ -57916,14 +58136,14 @@ duk_int_t duk_handle_call(duk_hthread *thr,
*/
DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
if (func) {
duk__update_func_caller_prop(thr, func);
}
act = thr->callstack + thr->callstack_top - 1;
#endif
- /* [... func this arg1 ... argN] */
+ /* [ ... func this arg1 ... argN ] */
/*
* Environment record creation and 'arguments' object creation.
@@ -57940,49 +58160,57 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
- if (func != NULL && !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)
- */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
-
- duk__handle_oldenv_for_call(thr, func, act);
+ if (DUK_LIKELY(func != NULL)) {
+ if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
+ if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
+ /* Use a new environment but there's no 'arguments' object;
+ * delayed environment initialization. This is the most
+ * common case.
+ */
+ DUK_ASSERT(act->lex_env == NULL);
+ DUK_ASSERT(act->var_env == NULL);
+ } else {
+ /* Use a new environment and there's an 'arguments' object.
+ * We need to initialize it right now.
+ */
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
- goto env_done;
- }
+ /* 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);
- DUK_ASSERT(func == NULL || DUK_HOBJECT_HAS_NEWENV(func));
+ /* [ ... func this arg1 ... argN envobj ] */
- if (func == NULL || !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;
- }
+ DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
+ duk__handle_createargs_for_call(thr, func, env, num_stack_args);
- /* 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);
+ /* [ ... func this arg1 ... argN envobj ] */
- /* [... func this arg1 ... argN envobj] */
+ act = thr->callstack + thr->callstack_top - 1;
+ 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);
+ }
+ } else {
+ /* Use existing env (e.g. for non-strict eval); cannot have
+ * an own 'arguments' object (but can refer to an existing one).
+ */
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
+ DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
- /* [... func this arg1 ... argN envobj] */
+ duk__handle_oldenv_for_call(thr, func, act);
- act = thr->callstack + thr->callstack_top - 1;
- 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_ASSERT(act->lex_env != NULL);
+ DUK_ASSERT(act->var_env != NULL);
+ }
+ } else {
+ /* Lightfuncs are always native functions and have "newenv". */
+ DUK_ASSERT(act->lex_env == NULL);
+ DUK_ASSERT(act->var_env == NULL);
+ }
- env_done:
- /* [... func this arg1 ... argN] */
+ /* [ ... func this arg1 ... argN ] */
/*
* Setup value stack: clamp to 'nargs', fill up to 'nregs'
@@ -57993,109 +58221,158 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* wants all args (= 'num_stack_args').
*/
+ /* XXX: optimize value stack operation */
+ /* XXX: don't want to shrink allocation here */
+
duk__adjust_valstack_and_top(thr,
num_stack_args,
- idx_args,
+ idx_func + 2,
nregs,
nargs,
func);
/*
- * Determine call type; then setup activation and call
+ * Determine call type, then finalize activation, shift to
+ * new value stack bottom, and call the target.
*/
if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- goto ecmascript_call;
- } else {
- goto native_call;
- }
- DUK_UNREACHABLE();
+ /*
+ * Ecmascript call
+ */
- /*
- * Native (C) call
- */
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- native_call:
- /*
- * Shift to new valstack_bottom.
- */
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
+ act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
- 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_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
+ 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);
- /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
+ /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
- /*
- * Actual function call and return value check.
- *
- * Return values:
- * 0 success, no return value (default to 'undefined')
- * 1 success, one return value on top of stack
- * < 0 error, throw a "magic" error
- * other invalid
- */
+ /*
+ * Bytecode executor call.
+ *
+ * Execute bytecode, handling any recursive function calls and
+ * thread resumptions. Returns when execution would return from
+ * the entry level activation. When the executor returns, a
+ * single return value is left on the stack top.
+ *
+ * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
+ * other types are handled internally by the executor.
+ */
- /* For native calls must be NULL so we don't sync back */
- DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ /* thr->ptr_curr_pc is set by bytecode executor early on entry */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
+ duk_js_execute_bytecode(thr);
+ DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
- if (func) {
- rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
- } else {
- duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
- rc = funcptr((duk_context *) thr);
- }
+ /* Unwind. */
- if (rc < 0) {
- duk_error_throw_from_negative_rc(thr, rc);
- DUK_UNREACHABLE();
- } else if (rc > 1) {
- DUK_ERROR_API(thr, "c function returned invalid rc");
- }
- DUK_ASSERT(rc == 0 || rc == 1);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ duk_hthread_catchstack_shrink_check(thr);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ duk_hthread_callstack_shrink_check(thr);
- /*
- * Unwind stack(s) and shift back to old valstack_bottom.
- */
+ 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);
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ /* Return value handling. */
-#if 0 /* should be no need to unwind */
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ /* [ ... 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(tv_funret);
#endif
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ } else {
+ /*
+ * Native call.
+ */
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- 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);
+ 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_hnativefunction *) func)->func != NULL);
- /*
- * Manipulate value stack so that return value is on top
- * (pushing an 'undefined' if necessary).
- */
+ /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
- /* XXX: should this happen in the callee's activation or after unwinding? */
- if (rc == 0) {
- duk_require_stack(ctx, 1);
- duk_push_undefined(ctx);
- }
- /* [... func this (crud) retval] */
+ /* For native calls must be NULL so we don't sync back */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
- DUK_DDD(DUK_DDDPRINT("native call retval -> %!T (rc=%ld)",
- (duk_tval *) duk_get_tval(ctx, -1), (long) rc));
+ if (func) {
+ rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
+ } else {
+ duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
+ rc = funcptr((duk_context *) thr);
+ }
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
+ /* Automatic error throwing, retval check. */
- /* [... retval] */
+ if (rc < 0) {
+ duk_error_throw_from_negative_rc(thr, rc);
+ DUK_UNREACHABLE();
+ } else if (rc > 1) {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "c function returned invalid rc");
+ }
+ DUK_ASSERT(rc == 0 || rc == 1);
+
+ /* Unwind. */
+
+ 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(thr, entry_callstack_top);
+ 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. */
+
+ /* 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;
+#if defined(DUK_USE_FASTINT)
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE(tv_funret);
+#endif
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ }
+ }
+
+ duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
+
+ /* [ ... retval ] */
/* Ensure there is internal valstack spare before we exit; this may
* throw an alloc error. The same guaranteed size must be available
@@ -58104,88 +58381,123 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* minimal guarantee for an application.
*/
+ /* 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.
+ */
+
(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;
- /*
- * Shrink checks and return with success.
- */
+ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
+ thr->state = (duk_uint8_t) entry_thread_state;
- retval = DUK_EXEC_SUCCESS;
- goto shrink_and_finished;
+ 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 */
- /*
- * Ecmascript call
+ 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_HEAP_IS_DEBUGGER_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
- ecmascript_call:
+#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
+ duk__interrupt_fixup(thr, entry_curr_thread);
+#endif
- /*
- * Shift to new valstack_bottom.
- */
+ return;
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
+ thread_state_error:
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+ return; /* never executed */
+}
+
+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
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ ) {
+ duk_context *ctx;
+ duk_tval *tv_ret;
- 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);
+ ctx = (duk_context *) thr;
- /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
+ DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
+ (duk_tval *) &thr->heap->lj.value1));
- /*
- * Bytecode executor call.
- *
- * Execute bytecode, handling any recursive function calls and
- * thread resumptions. Returns when execution would return from
- * the entry level activation. When the executor returns, a
- * single return value is left on the stack top.
- *
- * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
- * other types are handled internally by the executor.
- *
+ /* Other longjmp types are handled by executor before propagating
+ * the error here.
*/
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
- /* thr->ptr_curr_pc is set by bytecode executor early on entry */
+ /* 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);
- DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
- duk_js_execute_bytecode(thr);
- DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
- /*
- * Unwind stack(s) and shift back to old valstack_bottom.
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* 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;
+#endif
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
-
+ /* 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(thr, entry_catchstack_top);
+ duk_hthread_catchstack_shrink_check(thr);
duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ 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);
-
- /*
- * Manipulate value stack so that return value is on top.
- */
-
- /* [... func this (crud) retval] */
-
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
+ 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(tv_ret);
+#endif
+ duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
- /* [... retval] */
+ /* [ ... errobj ] */
/* Ensure there is internal valstack spare before we exit; this may
* throw an alloc error. The same guaranteed size must be available
@@ -58194,60 +58506,29 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* 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);
- /*
- * Shrink checks and return with success.
- */
- retval = DUK_EXEC_SUCCESS;
- goto shrink_and_finished;
-
- shrink_and_finished:
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- {
- duk_tval *tv_fi;
- tv_fi = duk_get_tval(ctx, -1);
- DUK_ASSERT(tv_fi != NULL);
- DUK_TVAL_CHKFAST_INPLACE(tv_fi);
- }
-#endif
-
- /* these are "soft" shrink checks, whose failures are ignored */
- /* XXX: would be nice if fast path was inlined */
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_shrink_check(thr);
- goto finished;
-
- finished:
- if (need_setjmp) {
- /* Note: either pointer may be NULL (at entry), so don't assert;
- * this is now done potentially twice, which is OK
- */
- DUK_DDD(DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p (possibly already done)",
- (void *) (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
- (void *) old_jmpbuf_ptr));
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- /* These are just convenience "wiping" of state */
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
-
- /* Side effects should not be an issue here: tv_tmp is local and
- * thr->heap (and thr->heap->lj) have a stable pointer. Finalizer
- * runs etc capture even out-of-memory errors so nothing should
- * throw here.
- */
- 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_DDD(DUK_DDDPRINT("setjmp catchpoint torn down"));
- }
+ /* 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;
@@ -58271,7 +58552,7 @@ duk_int_t duk_handle_call(duk_hthread *thr,
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_DD(DUK_DDPRINT("returning to ecmascript activation with debugger enabled, force interrupt"));
+ 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;
@@ -58282,119 +58563,25 @@ duk_int_t duk_handle_call(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
-
- return retval;
-
- thread_state_error:
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return DUK_EXEC_ERROR; /* never executed */
-}
-
-/*
- * Manipulate value stack so that exactly 'num_stack_rets' return
- * values are at 'idx_retbase' in every case, assuming there are
- * 'rc' return values on top of stack.
- *
- * This is a bit tricky, because the called C function operates in
- * the same activation record and may have e.g. popped the stack
- * empty (below idx_retbase).
- */
-
-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);
- DUK_ASSERT(idx_retbase >= 0);
- 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 */
-
- 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) 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
- */
- 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) {
- 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
- */
-
- DUK_ASSERT(count >= 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block remove primitive */
- duk_remove(ctx, idx_retbase);
- }
- } 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
- */
-
- DUK_ASSERT(count > 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block insert primitive */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_rcbase);
- }
- }
}
/*
- * Make a "C protected call" within the current activation.
+ * duk_handle_safe_call(): make a "C protected call" within the
+ * current activation.
*
* The allowed thread states for making a call are the same as for
- * duk_handle_call().
- *
- * Note that like duk_handle_call(), even if this call is protected,
- * there are a few situations where the current (pre-entry) setjmp
- * catcher (or a fatal error handler if no such catcher exists) is
- * invoked:
+ * duk_handle_call_xxx().
*
- * - Blatant API argument errors (e.g. num_stack_args is invalid,
- * so we can't form a reasonable return stack)
- *
- * - Errors during error handling, e.g. failure to reallocate
- * space in the value stack due to an alloc error
- *
- * Such errors propagate outwards, ultimately to the fatal error
- * handler if nothing else.
+ * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
+ * (and result in a fatal error) for insane arguments.
*/
/* 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,
- duk_idx_t num_stack_args,
- duk_idx_t num_stack_rets) {
+DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
+ duk_safe_call_function func,
+ duk_idx_t num_stack_args,
+ duk_idx_t num_stack_rets) {
duk_context *ctx = (duk_context *) thr;
duk_size_t entry_valstack_bottom_index;
duk_size_t entry_callstack_top;
@@ -58403,11 +58590,12 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
duk_hthread *entry_curr_thread;
duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *old_jmpbuf_ptr = NULL;
duk_jmpbuf our_jmpbuf;
+#endif
duk_idx_t idx_retbase;
duk_int_t retval;
- duk_ret_t rc;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(ctx != NULL);
@@ -58442,10 +58630,9 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
(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.
+ /* 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_API(thr, DUK_STR_INVALID_CALL_ARGS);
@@ -58453,74 +58640,136 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
/* setjmp catchpoint setup */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
+#endif
- if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
- goto handle_call;
- }
-
- /*
- * Error during call. The error value is at heap->lj.value1.
- *
- * Careful with variable accesses here; must be assigned to before
- * setjmp() or be declared volatile. See duk_handle_call().
- *
- * The following are such variables:
- * - duk_handle_safe_call() parameters
- * - entry_*
- * - idx_retbase
- *
- * The very first thing we do is restore the previous setjmp catcher.
- * This means that any error in error handling will propagate outwards
- * instead of causing a setjmp() re-entry above. The *only* actual
- * errors that should happen here are allocation errors.
- */
-
- DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
-
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- 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;
- * these are now restored twice which is OK.
- */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
-
- /* [ ... | (crud) ] */
-
- /* XXX: space in valstack? see discussion in duk_handle_call. */
- duk_push_tval(ctx, &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__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 */
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0)) {
+ /* Success path. */
+#endif
+ DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
+
+ duk__handle_safe_call_inner(thr,
+ func,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+
+ /* Longjmp state is kept clean in success path */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Note: either pointer may be NULL (at entry), so don't assert */
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- retval = DUK_EXEC_ERROR;
- goto shrink_and_finished;
+ retval = DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+ /* Error path. */
+#endif
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+
+ duk__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , old_jmpbuf_ptr
+#endif
+ );
+
+ /* Longjmp state is cleaned up by error handling */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+
+ 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(thr, DUK_ERR_API_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__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+ retval = DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "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__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+ retval = DUK_EXEC_ERROR;
+ }
+ }
+#endif
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
+#endif
+
+ 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);
- /*
- * Handle call (inside setjmp)
- */
+ return retval;
+}
- handle_call:
+DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
+ duk_safe_call_function func,
+ 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_context *ctx;
+ duk_ret_t rc;
- DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
+ 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);
/*
* Thread state check and book-keeping.
@@ -58583,7 +58832,7 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
/*
- * Valstack manipulation for results
+ * Valstack manipulation for results.
*/
/* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
@@ -58603,36 +58852,108 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_ERROR_API(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);
+ return;
- /* Note: no need from callstack / catchstack shrink check */
- retval = DUK_EXEC_SUCCESS;
- goto finished;
+ thread_state_error:
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+}
- shrink_and_finished:
- /* these are "soft" shrink checks, whose failures are ignored */
- /* XXX: would be nice if fast path was inlined */
+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
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ ) {
+ duk_context *ctx;
+
+ DUK_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+
+ /*
+ * Error during call. The error value is at heap->lj.value1.
+ *
+ * The very first thing we do is restore the previous setjmp catcher.
+ * This means that any error in error handling will propagate outwards
+ * instead of causing a setjmp() re-entry above.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
+
+ /* Other longjmp types are handled by executor before propagating
+ * the error here.
+ */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
+ 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. */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
+
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
duk_hthread_catchstack_shrink_check(thr);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
duk_hthread_callstack_shrink_check(thr);
- goto finished;
+ thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- finished:
- /* Note: either pointer may be NULL (at entry), so don't assert */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+ /* [ ... | (crud) ] */
- /* These are just convenience "wiping" of state */
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
+ /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
+ duk_push_tval(ctx, &thr->heap->lj.value1);
- /* Side effects should not be an issue here: tv_tmp is local and
- * thr->heap (and thr->heap->lj) have a stable pointer. Finalizer
- * runs etc capture even out-of-memory errors so nothing should
- * throw here.
+ /* [ ... | (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__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.
+ */
+ 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_DDD(DUK_DDDPRINT("setjmp catchpoint torn down"));
+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_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_UNREF(ctx);
+ DUK_UNREF(idx_retbase);
+ DUK_UNREF(num_stack_rets);
/* Restore entry thread executor curr_pc stack frame pointer. */
thr->ptr_curr_pc = entry_ptr_curr_pc;
@@ -58662,13 +58983,6 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
-
- return retval;
-
- thread_state_error:
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return DUK_EXEC_ERROR; /* never executed */
}
/*
@@ -58697,10 +59011,9 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
* 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_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) */
@@ -58740,7 +59053,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
* - an Ecmascript activation must be on top of the callstack
* - there cannot be any active catchstack entries
*/
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
duk_size_t our_callstack_index;
duk_size_t i;
@@ -58766,6 +59079,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
#endif /* DUK_USE_ASSERTIONS */
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;
@@ -58781,7 +59095,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
(long) idx_args,
(long) entry_valstack_bottom_index));
- if (idx_func < 0 || idx_args < 0) {
+ if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
/* XXX: assert? compiler is responsible for this never happening */
DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
}
@@ -58916,7 +59230,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
/* Start filling in the activation */
act->func = func; /* don't want an intermediate exposed state with func == NULL */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
DUK_ASSERT(func != NULL);
@@ -58927,13 +59241,13 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
act->prev_line = 0;
#endif
DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_HOBJECT_INCREF(thr, func);
act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
#endif
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#ifdef DUK_USE_TAILCALL
+#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
@@ -59019,7 +59333,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
act->func = func;
act->var_env = NULL;
act->lex_env = NULL;
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
DUK_ASSERT(func != NULL);
@@ -59037,14 +59351,14 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
DUK_HOBJECT_INCREF(thr, func); /* act->func */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
duk__update_func_caller_prop(thr, func);
act = thr->callstack + thr->callstack_top - 1;
#endif
}
- /* [... func this arg1 ... argN] (not tail call)
- * [this | arg1 ... argN] (tail call)
+ /* [ ... func this arg1 ... argN ] (not tail call)
+ * [ this | arg1 ... argN ] (tail call)
*
* idx_args updated to match
*/
@@ -59058,6 +59372,8 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
* Delayed creation (on demand) is handled in duk_js_var.c.
*/
+ /* XXX: unify handling with native call. */
+
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
if (!DUK_HOBJECT_HAS_NEWENV(func)) {
@@ -59085,7 +59401,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
DUK_ASSERT(env != NULL);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
/* original input stack before nargs/nregs handling must be
* intact for 'arguments' object
@@ -59093,7 +59409,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
duk__handle_createargs_for_call(thr, func, env, num_stack_args);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
act = thr->callstack + thr->callstack_top - 1;
act->lex_env = env;
@@ -59103,7 +59419,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
duk_pop(ctx);
env_done:
- /* [... arg1 ... argN] */
+ /* [ ... arg1 ... argN ] */
/*
* Setup value stack: clamp to 'nargs', fill up to 'nregs'
@@ -60056,8 +60372,8 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
*/
DUK_ASSERT(func->temp_max >= 0);
- h_res->nregs = func->temp_max;
- h_res->nargs = duk_hobject_get_length(thr, func->h_argnames);
+ h_res->nregs = (duk_uint16_t) func->temp_max;
+ h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
h_res->start_line = (duk_uint32_t) func->min_line;
@@ -67407,7 +67723,7 @@ DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_
#endif
}
-DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_small_uint_fast_t idx_z) {
+DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_uint_fast_t idx_z) {
/*
* E5 Section 11.4.8
*/
@@ -68311,6 +68627,9 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
* 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;
}
@@ -68895,16 +69214,66 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
thr->ptr_curr_pc = NULL; \
} while (0)
+DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
+ duk_hthread *entry_thread,
+ duk_size_t entry_callstack_top,
+ duk_int_t entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *entry_jmpbuf_ptr
+#endif
+ ) {
+ duk_small_uint_t lj_ret;
+
+ /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
+ * before longjmp.
+ */
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
+
+ /* XXX: signalling the need to shrink check (only if unwound) */
+
+ /* Must be restored here to handle e.g. yields properly. */
+ heap->call_recursion_depth = entry_call_recursion_depth;
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Switch to caller's setjmp() catcher so that if an error occurs
+ * during error handling, it is always propagated outwards instead
+ * of causing an infinite loop in our own handler.
+ */
+ heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
+#endif
+
+ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
+
+ if (lj_ret == DUK__LONGJMP_RESTART) {
+ /* Restart bytecode execution, possibly with a changed thread. */
+ ;
+ } else {
+ /* Rethrow error to calling state. */
+ DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Longjmp handling has restored jmpbuf_ptr. */
+ DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
+#endif
+
+ /* Thread may have changed, e.g. YIELD converted to THROW. */
+ duk_err_longjmp(heap->curr_thread);
+ DUK_UNREACHABLE();
+ }
+}
+
/* Outer executor with setjmp/longjmp handling. */
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_int_t entry_call_recursion_depth;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *entry_jmpbuf_ptr;
-
- duk_heap *heap;
duk_jmpbuf jmpbuf;
+#endif
+ duk_heap *heap;
DUK_ASSERT(exec_thr != NULL);
DUK_ASSERT(exec_thr->heap != NULL);
@@ -68918,7 +69287,9 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
heap = entry_thread->heap;
entry_callstack_top = entry_thread->callstack_top;
entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
+#endif
/*
* Note: we currently assume that the setjmp() catchpoint is
@@ -68930,55 +69301,83 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
*/
for (;;) {
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
heap->lj.jmpbuf_ptr = &jmpbuf;
DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
+#endif
- if (DUK_SETJMP(heap->lj.jmpbuf_ptr->jb) != 0) {
- duk_small_uint_t lj_ret;
-
- DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
-
- /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
- * before longjmp.
- */
- DUK_ASSERT(heap->curr_thread != NULL);
- DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
-
- /* XXX: signalling the need to shrink check (only if unwound) */
-
- /* Must be restored here to handle e.g. yields properly. */
- heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* Switch to caller's setjmp() catcher so that if an error occurs
- * during error handling, it is always propagated outwards instead
- * of causing an infinite loop in our own handler.
- */
- heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
-
- lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
-
- if (lj_ret == DUK__LONGJMP_RESTART) {
- /* Restart bytecode execution, possibly with a changed thread. */
- ;
- } else {
- /* Rethrow error to calling state. */
- DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
-
- /* Longjmp handling has restored jmpbuf_ptr. */
- DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
-
- /* Thread may have changed, e.g. YIELD converted to THROW. */
- duk_err_longjmp(heap->curr_thread);
- DUK_UNREACHABLE();
- }
- } else {
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(heap->lj.jmpbuf_ptr->jb) == 0)) {
+#endif
/* Execute bytecode until returned or longjmp(). */
duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
/* Successful return: restore jmpbuf and return to caller. */
heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
+#endif
+
return;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+ DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
+
+ duk__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
+#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_ASSERT(heap->curr_thread != NULL);
+ DUK_ERROR(heap->curr_thread, DUK_ERR_API_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__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ERROR(heap->curr_thread, DUK_ERR_API_ERROR, "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__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
}
+#endif
}
DUK_UNREACHABLE();
@@ -70238,9 +70637,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
*/
DUK_ASSERT(DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func) != duk_bi_global_object_eval);
- duk_handle_call(thr,
- num_stack_args,
- call_flags);
+ duk_handle_call_unprotected(thr,
+ num_stack_args,
+ call_flags);
/* duk_js_call.c is required to restore the stack reserve
* so we only need to reset the top.
@@ -70284,9 +70683,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
}
}
- duk_handle_call(thr,
- num_stack_args,
- call_flags);
+ duk_handle_call_unprotected(thr,
+ num_stack_args,
+ call_flags);
/* duk_js_call.c is required to restore the stack reserve
* so we only need to reset the top.
@@ -71136,7 +71535,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+#endif
duk_err_longjmp(thr);
DUK_UNREACHABLE();
}
@@ -71173,7 +71574,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+#endif
duk_err_longjmp(thr);
DUK_UNREACHABLE();
break;
@@ -74846,7 +75249,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(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "char decode failed");
+ DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "utf8 decode failed");
}
DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
@@ -75006,7 +75409,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(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "char decode failed");
+ DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "utf8 decode failed");
return 0;
}
@@ -77784,7 +78187,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
if (++t < nc_ctx->B) {
DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
- *p = t;
+ *p = (duk_uint8_t) t;
break;
}
@@ -87717,4 +88120,3 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
return t;
}
-#endif