http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-noline/metadata.json ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-noline/metadata.json b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-noline/metadata.json new file mode 100644 index 0000000..56ef280 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-noline/metadata.json @@ -0,0 +1,629 @@ +{ + "line_map": [ + { + "original_line": 1, + "combined_line": 114, + "original_file": "duk_internal.h" + }, + { + "original_line": 1, + "combined_line": 159, + "original_file": "duk_replacements.h" + }, + { + "original_line": 1, + "combined_line": 187, + "original_file": "duk_jmpbuf.h" + }, + { + "original_line": 1, + "combined_line": 211, + "original_file": "duk_exception.h" + }, + { + "original_line": 1, + "combined_line": 229, + "original_file": "duk_forwdecl.h" + }, + { + "original_line": 1, + "combined_line": 351, + "original_file": "duk_tval.h" + }, + { + "original_line": 1, + "combined_line": 869, + "original_file": "duk_builtins.h" + }, + { + "original_line": 52, + "combined_line": 1723, + "original_file": "duk_internal.h" + }, + { + "original_line": 1, + "combined_line": 1724, + "original_file": "duk_util.h" + }, + { + "original_line": 1, + "combined_line": 2254, + "original_file": "duk_strings.h" + }, + { + "original_line": 1, + "combined_line": 2506, + "original_file": "duk_js_bytecode.h" + }, + { + "original_line": 1, + "combined_line": 2711, + "original_file": "duk_lexer.h" + }, + { + "original_line": 1, + "combined_line": 3143, + "original_file": "duk_js_compiler.h" + }, + { + "original_line": 1, + "combined_line": 3370, + "original_file": "duk_regexp.h" + }, + { + "original_line": 1, + "combined_line": 3452, + "original_file": "duk_heaphdr.h" + }, + { + "original_line": 1, + "combined_line": 4202, + "original_file": "duk_api_internal.h" + }, + { + "original_line": 1, + "combined_line": 4396, + "original_file": "duk_hstring.h" + }, + { + "original_line": 1, + "combined_line": 4615, + "original_file": "duk_hobject.h" + }, + { + "original_line": 1, + "combined_line": 5541, + "original_file": "duk_hcompiledfunction.h" + }, + { + "original_line": 1, + "combined_line": 5780, + "original_file": "duk_hnativefunction.h" + }, + { + "original_line": 1, + "combined_line": 5812, + "original_file": "duk_hbufferobject.h" + }, + { + "original_line": 1, + "combined_line": 5945, + "original_file": "duk_hthread.h" + }, + { + "original_line": 1, + "combined_line": 6325, + "original_file": "duk_hbuffer.h" + }, + { + "original_line": 1, + "combined_line": 6653, + "original_file": "duk_heap.h" + }, + { + "original_line": 1, + "combined_line": 7249, + "original_file": "duk_debugger.h" + }, + { + "original_line": 1, + "combined_line": 7393, + "original_file": "duk_debug.h" + }, + { + "original_line": 1, + "combined_line": 7578, + "original_file": "duk_error.h" + }, + { + "original_line": 1, + "combined_line": 8017, + "original_file": "duk_unicode.h" + }, + { + "original_line": 1, + "combined_line": 8284, + "original_file": "duk_json.h" + }, + { + "original_line": 1, + "combined_line": 8352, + "original_file": "duk_js.h" + }, + { + "original_line": 1, + "combined_line": 8451, + "original_file": "duk_numconv.h" + }, + { + "original_line": 1, + "combined_line": 8541, + "original_file": "duk_bi_protos.h" + }, + { + "original_line": 1, + "combined_line": 8610, + "original_file": "duk_selftest.h" + }, + { + "original_line": 78, + "combined_line": 8622, + "original_file": "duk_internal.h" + }, + { + "original_line": 1, + "combined_line": 8624, + "original_file": "duk_replacements.c" + }, + { + "original_line": 1, + "combined_line": 8706, + "original_file": "duk_strings.c" + }, + { + "original_line": 1, + "combined_line": 8821, + "original_file": "duk_debug_macros.c" + }, + { + "original_line": 1, + "combined_line": 8965, + "original_file": "duk_builtins.c" + }, + { + "original_line": 1, + "combined_line": 9741, + "original_file": "duk_error_macros.c" + }, + { + "original_line": 1, + "combined_line": 9904, + "original_file": "duk_unicode_support.c" + }, + { + "original_line": 1, + "combined_line": 11077, + "original_file": "duk_util_misc.c" + }, + { + "original_line": 1, + "combined_line": 11299, + "original_file": "duk_util_hashprime.c" + }, + { + "original_line": 1, + "combined_line": 11376, + "original_file": "duk_hobject_class.c" + }, + { + "original_line": 1, + "combined_line": 11508, + "original_file": "duk_alloc_default.c" + }, + { + "original_line": 1, + "combined_line": 11542, + "original_file": "duk_api_buffer.c" + }, + { + "original_line": 1, + "combined_line": 11615, + "original_file": "duk_api_bytecode.c" + }, + { + "original_line": 1, + "combined_line": 12342, + "original_file": "duk_api_call.c" + }, + { + "original_line": 1, + "combined_line": 12897, + "original_file": "duk_api_codec.c" + }, + { + "original_line": 1, + "combined_line": 13535, + "original_file": "duk_api_compile.c" + }, + { + "original_line": 1, + "combined_line": 13729, + "original_file": "duk_api_debug.c" + }, + { + "original_line": 1, + "combined_line": 13992, + "original_file": "duk_api_heap.c" + }, + { + "original_line": 1, + "combined_line": 14126, + "original_file": "duk_api_logging.c" + }, + { + "original_line": 1, + "combined_line": 14178, + "original_file": "duk_api_memory.c" + }, + { + "original_line": 1, + "combined_line": 14281, + "original_file": "duk_api_object.c" + }, + { + "original_line": 1, + "combined_line": 14891, + "original_file": "duk_api_stack.c" + }, + { + "original_line": 1, + "combined_line": 19549, + "original_file": "duk_api_string.c" + }, + { + "original_line": 1, + "combined_line": 19880, + "original_file": "duk_api_var.c" + }, + { + "original_line": 1, + "combined_line": 19966, + "original_file": "duk_bi_array.c" + }, + { + "original_line": 1, + "combined_line": 21411, + "original_file": "duk_bi_boolean.c" + }, + { + "original_line": 1, + "combined_line": 21479, + "original_file": "duk_bi_buffer.c" + }, + { + "original_line": 1, + "combined_line": 24361, + "original_file": "duk_bi_date.c" + }, + { + "original_line": 1, + "combined_line": 26089, + "original_file": "duk_bi_date_unix.c" + }, + { + "original_line": 1, + "combined_line": 26398, + "original_file": "duk_bi_date_windows.c" + }, + { + "original_line": 1, + "combined_line": 26496, + "original_file": "duk_bi_duktape.c" + }, + { + "original_line": 1, + "combined_line": 26817, + "original_file": "duk_bi_error.c" + }, + { + "original_line": 1, + "combined_line": 27200, + "original_file": "duk_bi_function.c" + }, + { + "original_line": 1, + "combined_line": 27546, + "original_file": "duk_bi_global.c" + }, + { + "original_line": 1, + "combined_line": 28834, + "original_file": "duk_bi_json.c" + }, + { + "original_line": 1, + "combined_line": 31977, + "original_file": "duk_bi_logger.c" + }, + { + "original_line": 1, + "combined_line": 32277, + "original_file": "duk_bi_math.c" + }, + { + "original_line": 1, + "combined_line": 32625, + "original_file": "duk_bi_number.c" + }, + { + "original_line": 1, + "combined_line": 32865, + "original_file": "duk_bi_object.c" + }, + { + "original_line": 1, + "combined_line": 33442, + "original_file": "duk_bi_pointer.c" + }, + { + "original_line": 1, + "combined_line": 33516, + "original_file": "duk_bi_proxy.c" + }, + { + "original_line": 1, + "combined_line": 33582, + "original_file": "duk_bi_regexp.c" + }, + { + "original_line": 1, + "combined_line": 33791, + "original_file": "duk_bi_string.c" + }, + { + "original_line": 1, + "combined_line": 35105, + "original_file": "duk_bi_thread.c" + }, + { + "original_line": 1, + "combined_line": 35410, + "original_file": "duk_bi_thrower.c" + }, + { + "original_line": 1, + "combined_line": 35420, + "original_file": "duk_debug_fixedbuffer.c" + }, + { + "original_line": 1, + "combined_line": 35489, + "original_file": "duk_debug_heap.c" + }, + { + "original_line": 1, + "combined_line": 35736, + "original_file": "duk_debug_vsnprintf.c" + }, + { + "original_line": 1, + "combined_line": 36785, + "original_file": "duk_debugger.c" + }, + { + "original_line": 1, + "combined_line": 39558, + "original_file": "duk_error_augment.c" + }, + { + "original_line": 1, + "combined_line": 40125, + "original_file": "duk_error_longjmp.c" + }, + { + "original_line": 1, + "combined_line": 40170, + "original_file": "duk_error_misc.c" + }, + { + "original_line": 1, + "combined_line": 40302, + "original_file": "duk_error_throw.c" + }, + { + "original_line": 1, + "combined_line": 40483, + "original_file": "duk_hbuffer_alloc.c" + }, + { + "original_line": 1, + "combined_line": 40615, + "original_file": "duk_hbuffer_ops.c" + }, + { + "original_line": 2, + "combined_line": 40698, + "original_file": "duk_hbufferobject_misc.c" + }, + { + "original_line": 1, + "combined_line": 40717, + "original_file": "duk_heap_alloc.c" + }, + { + "original_line": 1, + "combined_line": 41759, + "original_file": "duk_heap_hashstring.c" + }, + { + "original_line": 1, + "combined_line": 41879, + "original_file": "duk_heap_markandsweep.c" + }, + { + "original_line": 1, + "combined_line": 43300, + "original_file": "duk_heap_memory.c" + }, + { + "original_line": 1, + "combined_line": 43684, + "original_file": "duk_heap_misc.c" + }, + { + "original_line": 1, + "combined_line": 43763, + "original_file": "duk_heap_refcount.c" + }, + { + "original_line": 1, + "combined_line": 44377, + "original_file": "duk_heap_stringcache.c" + }, + { + "original_line": 1, + "combined_line": 44675, + "original_file": "duk_heap_stringtable.c" + }, + { + "original_line": 1, + "combined_line": 45856, + "original_file": "duk_hobject_alloc.c" + }, + { + "original_line": 1, + "combined_line": 46048, + "original_file": "duk_hobject_enum.c" + }, + { + "original_line": 1, + "combined_line": 46674, + "original_file": "duk_hobject_finalizer.c" + }, + { + "original_line": 1, + "combined_line": 46784, + "original_file": "duk_hobject_misc.c" + }, + { + "original_line": 1, + "combined_line": 46836, + "original_file": "duk_hobject_pc2line.c" + }, + { + "original_line": 1, + "combined_line": 47086, + "original_file": "duk_hobject_props.c" + }, + { + "original_line": 1, + "combined_line": 53085, + "original_file": "duk_hstring_misc.c" + }, + { + "original_line": 1, + "combined_line": 53130, + "original_file": "duk_hthread_alloc.c" + }, + { + "original_line": 1, + "combined_line": 53225, + "original_file": "duk_hthread_builtins.c" + }, + { + "original_line": 1, + "combined_line": 54061, + "original_file": "duk_hthread_misc.c" + }, + { + "original_line": 1, + "combined_line": 54169, + "original_file": "duk_hthread_stacks.c" + }, + { + "original_line": 1, + "combined_line": 54645, + "original_file": "duk_js_call.c" + }, + { + "original_line": 1, + "combined_line": 57372, + "original_file": "duk_js_compiler.c" + }, + { + "original_line": 1, + "combined_line": 65237, + "original_file": "duk_js_executor.c" + }, + { + "original_line": 1, + "combined_line": 69744, + "original_file": "duk_js_ops.c" + }, + { + "original_line": 1, + "combined_line": 71114, + "original_file": "duk_js_var.c" + }, + { + "original_line": 1, + "combined_line": 72935, + "original_file": "duk_lexer.c" + }, + { + "original_line": 1, + "combined_line": 75002, + "original_file": "duk_numconv.c" + }, + { + "original_line": 1, + "combined_line": 77268, + "original_file": "duk_regexp_compiler.c" + }, + { + "original_line": 1, + "combined_line": 78340, + "original_file": "duk_regexp_executor.c" + }, + { + "original_line": 1, + "combined_line": 79348, + "original_file": "duk_selftest.c" + }, + { + "original_line": 2, + "combined_line": 79722, + "original_file": "duk_tval.c" + }, + { + "original_line": 1, + "combined_line": 79859, + "original_file": "duk_unicode_tables.c" + }, + { + "original_line": 1, + "combined_line": 85978, + "original_file": "duk_util_bitdecoder.c" + }, + { + "original_line": 1, + "combined_line": 86048, + "original_file": "duk_util_bitencoder.c" + }, + { + "original_line": 1, + "combined_line": 86091, + "original_file": "duk_util_bufwriter.c" + }, + { + "original_line": 1, + "combined_line": 86451, + "original_file": "duk_util_hashbytes.c" + }, + { + "original_line": 1, + "combined_line": 86508, + "original_file": "duk_util_tinyrandom.c" + } + ] +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_alloc_default.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_alloc_default.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_alloc_default.c new file mode 100644 index 0000000..d882bd7 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_alloc_default.c @@ -0,0 +1,34 @@ +/* + * Default allocation functions. + * + * Assumes behavior such as malloc allowing zero size, yielding + * a NULL or a unique pointer which is a no-op for free. + */ + +#include "duk_internal.h" + +#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) +DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) { + void *res; + DUK_UNREF(udata); + res = DUK_ANSI_MALLOC(size); + DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p", + (unsigned long) size, (void *) res)); + return res; +} + +DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) { + void *res; + DUK_UNREF(udata); + res = DUK_ANSI_REALLOC(ptr, newsize); + DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p", + (void *) ptr, (unsigned long) newsize, (void *) res)); + return res; +} + +DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) { + DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr)); + DUK_UNREF(udata); + DUK_ANSI_FREE(ptr); +} +#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_buffer.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_buffer.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_buffer.c new file mode 100644 index 0000000..3c12681 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_buffer.c @@ -0,0 +1,73 @@ +/* + * Buffer + */ + +#include "duk_internal.h" + +DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbuffer_dynamic *h; + + DUK_ASSERT_CTX_VALID(ctx); + + h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index); + DUK_ASSERT(h != NULL); + + if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { + DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + } + + /* maximum size check is handled by callee */ + duk_hbuffer_resize(thr, h, new_size); + + return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); +} + +DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbuffer_dynamic *h; + void *ptr; + duk_size_t sz; + + DUK_ASSERT(ctx != NULL); + + h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index); + DUK_ASSERT(h != NULL); + + if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { + DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + } + + /* Forget the previous allocation, setting size to 0 and alloc to + * NULL. Caller is responsible for freeing the previous allocation. + * Getting the allocation and clearing it is done in the same API + * call to avoid any chance of a realloc. + */ + ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); + sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h); + if (out_size) { + *out_size = sz; + } + DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h); + DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0); + + return ptr; +} + +DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_hbuffer_external *h; + + DUK_ASSERT(ctx != NULL); + + h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index); + DUK_ASSERT(h != NULL); + + if (!DUK_HBUFFER_HAS_EXTERNAL(h)) { + DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); + } + DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h)); + + DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr); + DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_bytecode.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_bytecode.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_bytecode.c new file mode 100644 index 0000000..bc2a295 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_bytecode.c @@ -0,0 +1,727 @@ +/* + * Bytecode dump/load + * + * The bytecode load primitive is more important performance-wise than the + * dump primitive. + * + * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be + * memory safe for invalid arguments - caller beware! There's little point + * in trying to achieve memory safety unless bytecode instructions are also + * validated which is not easy to do with indirect register references etc. + */ + +#include "duk_internal.h" + +#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT) + +#define DUK__SER_MARKER 0xff +#define DUK__SER_VERSION 0x00 +#define DUK__SER_STRING 0x00 +#define DUK__SER_NUMBER 0x01 +#define DUK__BYTECODE_INITIAL_ALLOC 256 + +/* + * Dump/load helpers, xxx_raw() helpers do no buffer checks + */ + +DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) { + duk_uint32_t len; + + len = DUK_RAW_READ_U32_BE(p); + duk_push_lstring(ctx, (const char *) p, len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) { + duk_uint32_t len; + duk_uint8_t *buf; + + len = DUK_RAW_READ_U32_BE(p); + buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); + DUK_ASSERT(buf != NULL); + DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) { + duk_size_t len; + duk_uint32_t tmp32; + + DUK_ASSERT(h != NULL); + + len = DUK_HSTRING_GET_BYTELEN(h); + DUK_ASSERT(len <= 0xffffffffUL); /* string limits */ + tmp32 = (duk_uint32_t) len; + DUK_RAW_WRITE_U32_BE(p, tmp32); + DUK_MEMCPY((void *) p, + (const void *) DUK_HSTRING_GET_DATA(h), + len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) { + duk_size_t len; + duk_uint32_t tmp32; + + DUK_ASSERT(thr != NULL); + DUK_ASSERT(h != NULL); + DUK_UNREF(thr); + + len = DUK_HBUFFER_GET_SIZE(h); + DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */ + tmp32 = (duk_uint32_t) len; + DUK_RAW_WRITE_U32_BE(p, tmp32); + DUK_MEMCPY((void *) p, + (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), + len); + p += len; + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { + duk_hstring *h_str; + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); + if (tv != NULL && DUK_TVAL_IS_STRING(tv)) { + h_str = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h_str != NULL); + } else { + h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); + DUK_ASSERT(h_str != NULL); + } + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p); + p = duk__dump_hstring_raw(p, h_str); + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); + if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) { + duk_hbuffer *h_buf; + h_buf = DUK_TVAL_GET_BUFFER(tv); + DUK_ASSERT(h_buf != NULL); + DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p); + p = duk__dump_hbuffer_raw(thr, p, h_buf); + } else { + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, 0); + } + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx, duk_uint32_t def_value) { + duk_tval *tv; + duk_uint32_t val; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); + if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) { + val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv); + } else { + val = def_value; + } + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, val); + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h; + duk_uint_fast32_t i; + + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + /* We know _Varmap only has own properties so walk property + * table directly. We also know _Varmap is dense and all + * values are numbers; assert for these. GC and finalizers + * shouldn't affect _Varmap so side effects should be fine. + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { + duk_hstring *key; + duk_tval *tv_val; + duk_uint32_t val; + + key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i); + DUK_ASSERT(key != NULL); /* _Varmap is dense */ + DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)); + tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i); + DUK_ASSERT(tv_val != NULL); + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */ +#if defined(DUK_USE_FASTINT) + DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val)); + DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */ + val = DUK_TVAL_GET_FASTINT_U32(tv_val); +#else + val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val); +#endif + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p); + p = duk__dump_hstring_raw(p, key); + DUK_RAW_WRITE_U32_BE(p, val); + } + } + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */ + return p; +} + +DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { + duk_tval *tv; + + tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr)); + if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { + duk_hobject *h; + duk_uint_fast32_t i; + + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + + /* We know _Formals is dense and all entries will be in the + * array part. GC and finalizers shouldn't affect _Formals + * so side effects should be fine. + */ + for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { + duk_tval *tv_val; + duk_hstring *varname; + + tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i); + DUK_ASSERT(tv_val != NULL); + if (DUK_TVAL_IS_STRING(tv_val)) { + /* Array is dense and contains only strings, but ASIZE may + * be larger than used part and there are UNUSED entries. + */ + varname = DUK_TVAL_GET_STRING(tv_val); + DUK_ASSERT(varname != NULL); + + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p); + p = duk__dump_hstring_raw(p, varname); + } + } + } + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); + DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */ + return p; +} + +static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) { + duk_hthread *thr; + duk_tval *tv, *tv_end; + duk_instr_t *ins, *ins_end; + duk_hobject **fn, **fn_end; + duk_hstring *h_str; + duk_uint32_t count_instr; + duk_uint32_t tmp32; + duk_uint16_t tmp16; + duk_double_t d; + + thr = (duk_hthread *) ctx; + DUK_UNREF(ctx); + DUK_UNREF(thr); + + DUK_DD(DUK_DDPRINT("dumping function %p to %p: " + "consts=[%p,%p[ (%ld bytes, %ld items), " + "funcs=[%p,%p[ (%ld bytes, %ld items), " + "code=[%p,%p[ (%ld bytes, %ld items)", + (void *) func, + (void *) p, + (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func), + (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func), + (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func))); + + DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */ + count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func); + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p); + + /* Fixed header info. */ + tmp32 = count_instr; + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func); + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func); + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp16 = func->nregs; + DUK_RAW_WRITE_U16_BE(p, tmp16); + tmp16 = func->nargs; + DUK_RAW_WRITE_U16_BE(p, tmp16); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + tmp32 = func->start_line; + DUK_RAW_WRITE_U32_BE(p, tmp32); + tmp32 = func->end_line; + DUK_RAW_WRITE_U32_BE(p, tmp32); +#else + DUK_RAW_WRITE_U32_BE(p, 0); + DUK_RAW_WRITE_U32_BE(p, 0); +#endif + tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK; + DUK_RAW_WRITE_U32_BE(p, tmp32); + + /* Bytecode instructions: endian conversion needed unless + * platform is big endian. + */ + ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func); + ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func); + DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr); +#if defined(DUK_USE_INTEGER_BE) + DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins)); + p += (size_t) (ins_end - ins); +#else + while (ins != ins_end) { + tmp32 = (duk_uint32_t) (*ins); + DUK_RAW_WRITE_U32_BE(p, tmp32); + ins++; + } +#endif + + /* Constants: variable size encoding. */ + tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func); + tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func); + while (tv != tv_end) { + /* constants are strings or numbers now */ + DUK_ASSERT(DUK_TVAL_IS_STRING(tv) || + DUK_TVAL_IS_NUMBER(tv)); + + if (DUK_TVAL_IS_STRING(tv)) { + h_str = DUK_TVAL_GET_STRING(tv); + DUK_ASSERT(h_str != NULL); + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p), + *p++ = DUK__SER_STRING; + p = duk__dump_hstring_raw(p, h_str); + } else { + DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p); + *p++ = DUK__SER_NUMBER; + d = DUK_TVAL_GET_NUMBER(tv); + DUK_RAW_WRITE_DOUBLE_BE(p, d); + } + tv++; + } + + /* Inner functions recursively. */ + fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func); + fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func); + while (fn != fn_end) { + /* XXX: This causes recursion up to inner function depth + * which is normally not an issue, e.g. mark-and-sweep uses + * a recursion limiter to avoid C stack issues. Avoiding + * this would mean some sort of a work list or just refusing + * to serialize deep functions. + */ + DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn)); + p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p); + fn++; + } + + /* Object extra properties. + * + * There are some difference between function templates and functions. + * For example, function templates don't have .length and nargs is + * normally used to instantiate the functions. + */ + + p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs); + p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME); + p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME); + p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE); + p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func); + p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func); + + DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p)); + + return p; +} + +/* Load a function from bytecode. The function object returned here must + * match what is created by duk_js_push_closure() with respect to its flags, + * properties, etc. + * + * NOTE: there are intentionally no input buffer length / bound checks. + * Adding them would be easy but wouldn't ensure memory safety as untrusted + * or broken bytecode is unsafe during execution unless the opcodes themselves + * are validated (which is quite complex, especially for indirect opcodes). + */ + +#define DUK__ASSERT_LEFT(n) do { \ + DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \ + } while (0) + +static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) { + duk_hthread *thr; + duk_hcompiledfunction *h_fun; + duk_hbuffer *h_data; + duk_size_t data_size; + duk_uint32_t count_instr, count_const, count_funcs; + duk_uint32_t n; + duk_uint32_t tmp32; + duk_small_uint_t const_type; + duk_uint8_t *fun_data; + duk_uint8_t *q; + duk_idx_t idx_base; + duk_tval *tv1; + duk_uarridx_t arr_idx; + + /* XXX: There's some overlap with duk_js_closure() here, but + * seems difficult to share code. Ensure that the final function + * looks the same as created by duk_js_closure(). + */ + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + + DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end)); + + DUK__ASSERT_LEFT(3 * 4); + count_instr = DUK_RAW_READ_U32_BE(p); + count_const = DUK_RAW_READ_U32_BE(p); + count_funcs = DUK_RAW_READ_U32_BE(p); + + data_size = sizeof(duk_tval) * count_const + + sizeof(duk_hobject *) * count_funcs + + sizeof(duk_instr_t) * count_instr; + + DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld", + (long) count_instr, (long) count_const, + (long) count_const, (long) data_size)); + + /* Value stack is used to ensure reachability of constants and + * inner functions being loaded. Require enough space to handle + * large functions correctly. + */ + duk_require_stack(ctx, 2 + count_const + count_funcs); + idx_base = duk_get_top(ctx); + + /* Push function object, init flags etc. This must match + * duk_js_push_closure() quite carefully. + */ + duk_push_compiledfunction(ctx); + h_fun = duk_get_hcompiledfunction(ctx, -1); + DUK_ASSERT(h_fun != NULL); + DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun)); + DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL); + DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL); + + h_fun->nregs = DUK_RAW_READ_U16_BE(p); + h_fun->nargs = DUK_RAW_READ_U16_BE(p); +#if defined(DUK_USE_DEBUGGER_SUPPORT) + h_fun->start_line = DUK_RAW_READ_U32_BE(p); + h_fun->end_line = DUK_RAW_READ_U32_BE(p); +#else + p += 8; /* skip line info */ +#endif + + /* duk_hcompiledfunction flags; quite version specific */ + tmp32 = DUK_RAW_READ_U32_BE(p); + DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); + + /* standard prototype */ + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); + + /* assert just a few critical flags */ + DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT); + DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj)); + DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj)); + DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj)); + + /* Create function 'data' buffer but don't attach it yet. */ + fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size); + DUK_ASSERT(fun_data != NULL); + + /* Load bytecode instructions. */ + DUK_ASSERT(sizeof(duk_instr_t) == 4); + DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t)); +#if defined(DUK_USE_INTEGER_BE) + q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; + DUK_MEMCPY((void *) q, + (const void *) p, + sizeof(duk_instr_t) * count_instr); + p += sizeof(duk_instr_t) * count_instr; +#else + q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; + for (n = count_instr; n > 0; n--) { + *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p); + q += sizeof(duk_instr_t); + } +#endif + + /* Load constants onto value stack but don't yet copy to buffer. */ + for (n = count_const; n > 0; n--) { + DUK__ASSERT_LEFT(1); + const_type = DUK_RAW_READ_U8(p); + switch (const_type) { + case DUK__SER_STRING: { + p = duk__load_string_raw(ctx, p); + break; + } + case DUK__SER_NUMBER: { + /* Important to do a fastint check so that constants are + * properly read back as fastints. + */ + duk_tval tv_tmp; + duk_double_t val; + DUK__ASSERT_LEFT(8); + val = DUK_RAW_READ_DOUBLE_BE(p); + DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val); + duk_push_tval(ctx, &tv_tmp); + break; + } + default: { + goto format_error; + } + } + } + + /* Load inner functions to value stack, but don't yet copy to buffer. */ + for (n = count_funcs; n > 0; n--) { + p = duk__load_func(ctx, p, p_end); + if (p == NULL) { + goto format_error; + } + } + + /* With constants and inner functions on value stack, we can now + * atomically finish the function 'data' buffer, bump refcounts, + * etc. + * + * Here we take advantage of the value stack being just a duk_tval + * array: we can just memcpy() the constants as long as we incref + * them afterwards. + */ + + h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1); + DUK_ASSERT(h_data != NULL); + DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data)); + DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data); + DUK_HBUFFER_INCREF(thr, h_data); + + tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */ + DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL); + + q = fun_data; + if (count_const > 0) { + /* Explicit zero size check to avoid NULL 'tv1'. */ + DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const); + for (n = count_const; n > 0; n--) { + DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */ + q += sizeof(duk_tval); + } + tv1 += count_const; + } + + DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q); + for (n = count_funcs; n > 0; n--) { + duk_hobject *h_obj; + + DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1)); + h_obj = DUK_TVAL_GET_OBJECT(tv1); + DUK_ASSERT(h_obj != NULL); + tv1++; + DUK_HOBJECT_INCREF(thr, h_obj); + + *((duk_hobject **) (void *) q) = h_obj; + q += sizeof(duk_hobject *); + } + + DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q); + + /* The function object is now reachable and refcounts are fine, + * so we can pop off all the temporaries. + */ + DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base))); + duk_set_top(ctx, idx_base + 1); + + /* Setup function properties. */ + tmp32 = DUK_RAW_READ_U32_BE(p); + duk_push_u32(ctx, tmp32); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); + + p = duk__load_string_raw(ctx, p); + if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) { + /* Original function instance/template had NAMEBINDING. + * Must create a lexical environment on loading to allow + * recursive functions like 'function foo() { foo(); }'. + */ + duk_hobject *proto; + + proto = thr->builtins[DUK_BIDX_GLOBAL_ENV]; + (void) duk_push_object_helper_proto(ctx, + DUK_HOBJECT_FLAG_EXTENSIBLE | + DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV), + proto); + duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */ + duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */ + duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */ + duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC); + /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it + * will be ignored anyway + */ + } + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); + + p = duk__load_string_raw(ctx, p); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC); + + duk_push_object(ctx); + duk_dup(ctx, -2); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */ + duk_compact(ctx, -1); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); + + p = duk__load_buffer_raw(ctx, p); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC); + + duk_push_object(ctx); /* _Varmap */ + for (;;) { + /* XXX: awkward */ + p = duk__load_string_raw(ctx, p); + if (duk_get_length(ctx, -1) == 0) { + duk_pop(ctx); + break; + } + tmp32 = DUK_RAW_READ_U32_BE(p); + duk_push_u32(ctx, tmp32); + duk_put_prop(ctx, -3); + } + duk_compact(ctx, -1); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); + + duk_push_array(ctx); /* _Formals */ + for (arr_idx = 0; ; arr_idx++) { + /* XXX: awkward */ + p = duk__load_string_raw(ctx, p); + if (duk_get_length(ctx, -1) == 0) { + duk_pop(ctx); + break; + } + duk_put_prop_index(ctx, -2, arr_idx); + } + duk_compact(ctx, -1); + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); + + /* Return with final function pushed on stack top. */ + DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1))); + DUK_ASSERT_TOP(ctx, idx_base + 1); + return p; + + format_error: + return NULL; +} + +DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { + duk_hthread *thr; + duk_hcompiledfunction *func; + duk_bufwriter_ctx bw_ctx_alloc; + duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc; + duk_uint8_t *p; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + + /* Bound functions don't have all properties so we'd either need to + * lookup the non-bound target function or reject bound functions. + * For now, bound functions are rejected. + */ + func = duk_require_hcompiledfunction(ctx, -1); + DUK_ASSERT(func != NULL); + DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj)); + + /* Estimating the result size beforehand would be costly, so + * start with a reasonable size and extend as needed. + */ + DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC); + p = DUK_BW_GET_PTR(thr, bw_ctx); + *p++ = DUK__SER_MARKER; + *p++ = DUK__SER_VERSION; + p = duk__dump_func(ctx, func, bw_ctx, p); + DUK_BW_SET_PTR(thr, bw_ctx, p); + DUK_BW_COMPACT(thr, bw_ctx); + + DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1))); + + duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */ +} + +DUK_EXTERNAL void duk_load_function(duk_context *ctx) { + duk_hthread *thr; + duk_uint8_t *p_buf, *p, *p_end; + duk_size_t sz; + + DUK_ASSERT(ctx != NULL); + thr = (duk_hthread *) ctx; + DUK_UNREF(ctx); + + p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz); + DUK_ASSERT(p_buf != NULL); + + /* The caller is responsible for being sure that bytecode being loaded + * is valid and trusted. Invalid bytecode can cause memory unsafe + * behavior directly during loading or later during bytecode execution + * (instruction validation would be quite complex to implement). + * + * This signature check is the only sanity check for detecting + * accidental invalid inputs. The initial 0xFF byte ensures no + * ordinary string will be accepted by accident. + */ + p = p_buf; + p_end = p_buf + sz; + if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) { + goto format_error; + } + p += 2; + + p = duk__load_func(ctx, p, p_end); + if (p == NULL) { + goto format_error; + } + + duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */ + return; + + format_error: + DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); +} + +#undef DUK__SER_MARKER +#undef DUK__SER_VERSION +#undef DUK__SER_STRING +#undef DUK__SER_NUMBER +#undef DUK__BYTECODE_INITIAL_ALLOC + +#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */ + +DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { + DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx); +} + +DUK_EXTERNAL void duk_load_function(duk_context *ctx) { + DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx); +} + +#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_call.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_call.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_call.c new file mode 100644 index 0000000..25dac14 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_call.c @@ -0,0 +1,555 @@ +/* + * Calls. + * + * Protected variants should avoid ever throwing an error. + */ + +#include "duk_internal.h" + +/* Prepare value stack for a method call through an object property. + * May currently throw an error e.g. when getting the property. + */ +DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) { + DUK_ASSERT_CTX_VALID(ctx); + + DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld", + (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx))); + + /* [... key arg1 ... argN] */ + + /* duplicate key */ + duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */ + duk_get_prop(ctx, normalized_obj_index); + + DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1))); + + /* [... key arg1 ... argN func] */ + + duk_replace(ctx, -nargs - 2); + + /* [... func arg1 ... argN] */ + + duk_dup(ctx, normalized_obj_index); + duk_insert(ctx, -nargs - 1); + + /* [... func this arg1 ... argN] */ +} + +DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_uint_t call_flags; + duk_idx_t idx_func; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 1; + if (idx_func < 0 || nargs < 0) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + } + + /* XXX: awkward; we assume there is space for this, overwrite + * directly instead? + */ + duk_push_undefined(ctx); + duk_insert(ctx, idx_func + 1); + + call_flags = 0; /* not protected, respect reclimit, not constructor */ + + duk_handle_call_unprotected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ +} + +DUK_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_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ + if (idx_func < 0 || nargs < 0) { + /* note that we can't reliably pop anything here */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + } + + call_flags = 0; /* not protected, respect reclimit, not constructor */ + + 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) { + /* + * XXX: if duk_handle_call() took values through indices, this could be + * made much more sensible. However, duk_handle_call() needs to fudge + * the 'this' and 'func' values to handle bound function chains, which + * is now done "in-place", so this is not a trivial change. + */ + + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */ + + duk__call_prop_prep_stack(ctx, obj_index, nargs); + + duk_call_method(ctx, nargs); +} + +DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_uint_t call_flags; + duk_idx_t idx_func; + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */ + if (idx_func < 0 || nargs < 0) { + /* We can't reliably pop anything here because the stack input + * shape is incorrect. So we throw an error; if the caller has + * no catch point for this, a fatal error will occur. Another + * alternative would be to just return an error. But then the + * stack would be in an unknown state which might cause some + * very hard to diagnose problems later on. Also note that even + * if we did not throw an error here, the underlying call handler + * might STILL throw an out-of-memory error or some other internal + * fatal error. + */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return DUK_EXEC_ERROR; /* unreachable */ + } + + /* awkward; we assume there is space for this */ + duk_push_undefined(ctx); + duk_insert(ctx, idx_func + 1); + + call_flags = 0; /* respect reclimit, not constructor */ + + rc = duk_handle_call_protected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ + + return rc; +} + +DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_small_uint_t call_flags; + duk_idx_t idx_func; + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ + if (idx_func < 0 || nargs < 0) { + /* See comments in duk_pcall(). */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return DUK_EXEC_ERROR; /* unreachable */ + } + + call_flags = 0; /* respect reclimit, not constructor */ + + rc = duk_handle_call_protected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ + + return rc; +} + +DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) { + duk_idx_t obj_index; + duk_idx_t nargs; + + /* Get the original arguments. Note that obj_index may be a relative + * index so the stack must have the same top when we use it. + */ + + DUK_ASSERT_CTX_VALID(ctx); + + obj_index = (duk_idx_t) duk_get_int(ctx, -2); + nargs = (duk_idx_t) duk_get_int(ctx, -1); + duk_pop_2(ctx); + + obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */ + duk__call_prop_prep_stack(ctx, obj_index, nargs); + duk_call_method(ctx, nargs); + return 1; +} + +DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) { + /* + * Must be careful to catch errors related to value stack manipulation + * and property lookup, not just the call itself. + */ + + DUK_ASSERT_CTX_VALID(ctx); + + duk_push_idx(ctx, obj_index); + duk_push_idx(ctx, nargs); + + /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing. + * If the value stack does not contain enough args, an error is thrown; this matches + * behavior of the other protected call API functions. + */ + return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/); +} + +DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + + if (duk_get_top(ctx) < nargs || nrets < 0) { + /* See comments in duk_pcall(). */ + DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS); + return DUK_EXEC_ERROR; /* unreachable */ + } + + rc = duk_handle_safe_call(thr, /* thread */ + func, /* func */ + nargs, /* num_stack_args */ + nrets); /* num_stack_res */ + + return rc; +} + +DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) { + /* + * There are two [[Construct]] operations in the specification: + * + * - E5 Section 13.2.2: for Function objects + * - E5 Section 15.3.4.5.2: for "bound" Function objects + * + * The chain of bound functions is resolved in Section 15.3.4.5.2, + * with arguments "piling up" until the [[Construct]] internal + * method is called on the final, actual Function object. Note + * that the "prototype" property is looked up *only* from the + * final object, *before* calling the constructor. + * + * Currently we follow the bound function chain here to get the + * "prototype" property value from the final, non-bound function. + * However, we let duk_handle_call() handle the argument "piling" + * when the constructor is called. The bound function chain is + * thus now processed twice. + * + * When constructing new Array instances, an unnecessary object is + * created and discarded now: the standard [[Construct]] creates an + * object, and calls the Array constructor. The Array constructor + * returns an Array instance, which is used as the result value for + * the "new" operation; the object created before the Array constructor + * call is discarded. + * + * This would be easy to fix, e.g. by knowing that the Array constructor + * will always create a replacement object and skip creating the fallback + * object in that case. + * + * Note: functions called via "new" need to know they are called as a + * constructor. For instance, built-in constructors behave differently + * depending on how they are called. + */ + + /* XXX: merge this with duk_js_call.c, as this function implements + * core semantics (or perhaps merge the two files altogether). + */ + + duk_hthread *thr = (duk_hthread *) ctx; + duk_hobject *proto; + duk_hobject *cons; + duk_hobject *fallback; + duk_idx_t idx_cons; + duk_small_uint_t call_flags; + + DUK_ASSERT_CTX_VALID(ctx); + + /* [... constructor arg1 ... argN] */ + + idx_cons = duk_require_normalize_index(ctx, -nargs - 1); + + DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld", + (long) duk_get_top(ctx), (long) nargs, (long) idx_cons)); + + /* XXX: code duplication */ + + /* + * Figure out the final, non-bound constructor, to get "prototype" + * property. + */ + + duk_dup(ctx, idx_cons); + for (;;) { + duk_tval *tv; + tv = DUK_GET_TVAL_NEGIDX(ctx, -1); + DUK_ASSERT(tv != NULL); + + if (DUK_TVAL_IS_OBJECT(tv)) { + cons = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(cons != NULL); + if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) { + /* Checking callability of the immediate target + * is important, same for constructability. + * Checking it for functions down the bound + * function chain is not strictly necessary + * because .bind() should normally reject them. + * But it's good to check anyway because it's + * technically possible to edit the bound function + * chain via internal keys. + */ + goto not_constructable; + } + if (!DUK_HOBJECT_HAS_BOUND(cons)) { + break; + } + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + /* Lightfuncs cannot be bound. */ + break; + } else { + /* Anything else is not constructable. */ + goto not_constructable; + } + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */ + duk_remove(ctx, -2); /* -> [... target] */ + } + DUK_ASSERT(duk_is_callable(ctx, -1)); + DUK_ASSERT(duk_is_lightfunc(ctx, -1) || + (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUND(duk_get_hobject(ctx, -1)))); + + /* [... constructor arg1 ... argN final_cons] */ + + /* + * Create "fallback" object to be used as the object instance, + * unless the constructor returns a replacement value. + * Its internal prototype needs to be set based on "prototype" + * property of the constructor. + */ + + duk_push_object(ctx); /* class Object, extensible */ + + /* [... constructor arg1 ... argN final_cons fallback] */ + + duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE); + proto = duk_get_hobject(ctx, -1); + if (!proto) { + DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object " + "-> leave standard Object prototype as fallback prototype")); + } else { + DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value " + "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto)); + fallback = duk_get_hobject(ctx, -2); + DUK_ASSERT(fallback != NULL); + DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto); + } + duk_pop(ctx); + + /* [... constructor arg1 ... argN final_cons fallback] */ + + /* + * Manipulate callstack for the call. + */ + + duk_dup_top(ctx); + duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */ + duk_insert(ctx, idx_cons); /* also stash it before constructor, + * in case we need it (as the fallback value) + */ + duk_pop(ctx); /* pop final_cons */ + + + /* [... fallback constructor fallback(this) arg1 ... argN]; + * Note: idx_cons points to first 'fallback', not 'constructor'. + */ + + DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, " + "nargs=%ld, top=%ld", + (duk_tval *) duk_get_tval(ctx, idx_cons + 1), + (duk_tval *) duk_get_tval(ctx, idx_cons + 2), + (long) nargs, + (long) duk_get_top(ctx))); + + /* + * Call the constructor function (called in "constructor mode"). + */ + + call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */ + + duk_handle_call_unprotected(thr, /* thread */ + nargs, /* num_stack_args */ + call_flags); /* call_flags */ + + /* [... fallback retval] */ + + DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT", + (duk_tval *) duk_get_tval(ctx, -2), + (duk_tval *) duk_get_tval(ctx, -1))); + + /* + * Determine whether to use the constructor return value as the created + * object instance or not. + */ + + if (duk_is_object(ctx, -1)) { + duk_remove(ctx, -2); + } else { + duk_pop(ctx); + } + + /* + * Augment created errors upon creation (not when they are thrown or + * rethrown). __FILE__ and __LINE__ are not desirable here; the call + * stack reflects the caller which is correct. + */ + +#ifdef DUK_USE_AUGMENT_ERROR_CREATE + duk_hthread_sync_currpc(thr); + duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/); +#endif + + /* [... retval] */ + + return; + + not_constructable: + DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE); +} + +DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) { + duk_uint_t nargs; + + nargs = duk_to_uint(ctx, -1); + duk_pop(ctx); + + duk_new(ctx, nargs); + return 1; +} + +DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { + duk_int_t rc; + + DUK_ASSERT_CTX_VALID(ctx); + + /* For now, just use duk_safe_call() to wrap duk_new(). We can't + * simply use a protected duk_handle_call() because there's post + * processing which might throw. It should be possible to ensure + * the post processing never throws (except in internal errors and + * out of memory etc which are always allowed) and then remove this + * wrapper. + */ + + duk_push_uint(ctx, nargs); + rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/); + return rc; +} + +DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); + + act = duk_hthread_get_current_activation(thr); + DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ + return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); +} + +DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + + /* For user code this could just return 1 (strict) always + * because all Duktape/C functions are considered strict, + * and strict is also the default when nothing is running. + * However, Duktape may call this function internally when + * the current activation is an Ecmascript function, so + * this cannot be replaced by a 'return 1' without fixing + * the internal call sites. + */ + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); + + act = duk_hthread_get_current_activation(thr); + if (act == NULL) { + /* Strict by default. */ + return 1; + } + return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); +} + +/* + * Duktape/C function magic + */ + +DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_activation *act; + duk_hobject *func; + + DUK_ASSERT_CTX_VALID(ctx); + DUK_ASSERT(thr != NULL); + DUK_ASSERT_DISABLE(thr->callstack_top >= 0); + + act = duk_hthread_get_current_activation(thr); + if (act) { + func = DUK_ACT_GET_FUNC(act); + if (!func) { + duk_tval *tv = &act->tv_func; + duk_small_uint_t lf_flags; + lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); + return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); + } + DUK_ASSERT(func != NULL); + + if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) { + duk_hnativefunction *nf = (duk_hnativefunction *) func; + return (duk_int_t) nf->magic; + } + } + return 0; +} + +DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_tval *tv; + duk_hobject *h; + + DUK_ASSERT_CTX_VALID(ctx); + + tv = duk_require_tval(ctx, index); + if (DUK_TVAL_IS_OBJECT(tv)) { + h = DUK_TVAL_GET_OBJECT(tv); + DUK_ASSERT(h != NULL); + if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) { + goto type_error; + } + return (duk_int_t) ((duk_hnativefunction *) h)->magic; + } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { + duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); + return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); + } + + /* fall through */ + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); + return 0; +} + +DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) { + duk_hnativefunction *nf; + + DUK_ASSERT_CTX_VALID(ctx); + + nf = duk_require_hnativefunction(ctx, index); + DUK_ASSERT(nf != NULL); + nf->magic = (duk_int16_t) magic; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_codec.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_codec.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_codec.c new file mode 100644 index 0000000..5fa0bb8 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_api_codec.c @@ -0,0 +1,638 @@ +/* + * Encoding and decoding basic formats: hex, base64. + * + * These are in-place operations which may allow an optimized implementation. + * + * Base-64: https://tools.ietf.org/html/rfc4648#section-4 + */ + +#include "duk_internal.h" + +/* Shared handling for encode/decode argument. Fast path handling for + * buffer and string values because they're the most common. In particular, + * avoid creating a temporary string or buffer when possible. + */ +DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) { + DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */ + if (duk_is_buffer(ctx, index)) { + return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len); + } else { + return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len); + } +} + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { + duk_uint_t t; + duk_size_t n_full, n_full3, n_final; + const duk_uint8_t *src_end_fast; + + n_full = srclen / 3; /* full 3-byte -> 4-char conversions */ + n_full3 = n_full * 3; + n_final = srclen - n_full3; + DUK_ASSERT_DISABLE(n_final >= 0); + DUK_ASSERT(n_final <= 2); + + src_end_fast = src + n_full3; + while (DUK_UNLIKELY(src != src_end_fast)) { + t = (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + + *dst++ = duk_base64_enctab[t >> 18]; + *dst++ = duk_base64_enctab[(t >> 12) & 0x3f]; + *dst++ = duk_base64_enctab[(t >> 6) & 0x3f]; + *dst++ = duk_base64_enctab[t & 0x3f]; + +#if 0 /* Tested: not faster on x64 */ + /* aaaaaabb bbbbcccc ccdddddd */ + dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f]; + dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)]; + dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)]; + dst[3] = duk_base64_enctab[src[2] & 0x3f]; + src += 3; dst += 4; +#endif + } + + switch (n_final) { + /* case 0: nop */ + case 1: { + /* XX== */ + t = (duk_uint_t) (*src++); + *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */ + *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */ + *dst++ = DUK_ASC_EQUALS; + *dst++ = DUK_ASC_EQUALS; + break; + } + case 2: { + /* XXX= */ + t = (duk_uint_t) (*src++); + t = (t << 8) + (duk_uint_t) (*src++); + *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */ + *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */ + *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */ + *dst++ = DUK_ASC_EQUALS; + break; + } + } +} +#else /* DUK_USE_BASE64_FASTPATH */ +DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { + duk_small_uint_t i, snip; + duk_uint_t t; + duk_uint_fast8_t x, y; + const duk_uint8_t *src_end; + + src_end = src + srclen; + + while (src < src_end) { + /* read 3 bytes into 't', padded by zero */ + snip = 4; + t = 0; + for (i = 0; i < 3; i++) { + t = t << 8; + if (src >= src_end) { + snip--; + } else { + t += (duk_uint_t) (*src++); + } + } + + /* + * Missing bytes snip base64 example + * 0 4 XXXX + * 1 3 XXX= + * 2 2 XX== + */ + + DUK_ASSERT(snip >= 2 && snip <= 4); + + for (i = 0; i < 4; i++) { + x = (duk_uint_fast8_t) ((t >> 18) & 0x3f); + t = t << 6; + + /* A straightforward 64-byte lookup would be faster + * and cleaner, but this is shorter. + */ + if (i >= snip) { + y = '='; + } else if (x <= 25) { + y = x + 'A'; + } else if (x <= 51) { + y = x - 26 + 'a'; + } else if (x <= 61) { + y = x - 52 + '0'; + } else if (x == 62) { + y = '+'; + } else { + y = '/'; + } + + *dst++ = (duk_uint8_t) y; + } + } +} +#endif /* DUK_USE_BASE64_FASTPATH */ + +#if defined(DUK_USE_BASE64_FASTPATH) +DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { + duk_int_t x; + duk_int_t t; + duk_small_uint_t n_equal; + duk_small_uint_t n_chars; + const duk_uint8_t *src_end; + const duk_uint8_t *src_end_safe; + + src_end = src + srclen; + src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */ + + /* Innermost fast path processes 4 valid base-64 characters at a time + * but bails out on whitespace, padding chars ('=') and invalid chars. + * Once the slow path segment has been processed, we return to the + * inner fast path again. This handles e.g. base64 with newlines + * reasonably well because the majority of a line is in the fast path. + */ + for (;;) { + /* Fast path, handle units with just actual encoding characters. */ + + while (src <= src_end_safe) { + /* The lookup byte is intentionally sign extended to (at least) + * 32 bits and then ORed. This ensures that is at least 1 byte + * is negative, the highest bit of 't' will be set at the end + * and we don't need to check every byte. + */ + DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p", + (const void *) src, (const void *) src_end_safe, (const void *) src_end)); + + t = (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++]; + + if (DUK_UNLIKELY(t < 0)) { + DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit")); + src -= 4; + break; + } + + DUK_ASSERT(t <= 0xffffffL); + DUK_ASSERT((t >> 24) == 0); + *dst++ = (duk_uint8_t) (t >> 16); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + } + + /* Handle one slow path unit (or finish if we're done). */ + + n_equal = 0; + n_chars = 0; + t = 0; + for (;;) { + DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld", + (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t)); + + if (DUK_UNLIKELY(src >= src_end)) { + goto done; /* two level break */ + } + + x = duk_base64_dectab[*src++]; + if (DUK_UNLIKELY(x < 0)) { + if (x == -2) { + continue; /* allowed ascii whitespace */ + } else if (x == -3) { + n_equal++; + t <<= 6; + } else { + DUK_ASSERT(x == -1); + goto error; + } + } else { + DUK_ASSERT(x >= 0 && x <= 63); + if (n_equal > 0) { + /* Don't allow actual chars after equal sign. */ + goto error; + } + t = (t << 6) + x; + } + + if (DUK_UNLIKELY(n_chars == 3)) { + /* Emit 3 bytes and backtrack if there was padding. There's + * always space for the whole 3 bytes so no check needed. + */ + DUK_ASSERT(t <= 0xffffffL); + DUK_ASSERT((t >> 24) == 0); + *dst++ = (duk_uint8_t) (t >> 16); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + + if (DUK_UNLIKELY(n_equal > 0)) { + DUK_ASSERT(n_equal <= 4); + + /* There may be whitespace between the equal signs. */ + if (n_equal == 1) { + /* XXX= */ + dst -= 1; + } else if (n_equal == 2) { + /* XX== */ + dst -= 2; + } else { + goto error; /* invalid padding */ + } + + /* Continue parsing after padding, allows concatenated, + * padded base64. + */ + } + break; /* back to fast loop */ + } else { + n_chars++; + } + } + } + done: + DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld", + (const void *) src, (const void *) src_end, (long) n_chars)); + + DUK_ASSERT(src == src_end); + + if (n_chars != 0) { + /* Here we'd have the option of decoding unpadded base64 + * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not + * accepted. + */ + goto error; + } + + *out_dst_final = dst; + return 1; + + error: + return 0; +} +#else /* DUK_USE_BASE64_FASTPATH */ +DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { + duk_uint_t t; + duk_uint_fast8_t x, y; + duk_small_uint_t group_idx; + duk_small_uint_t n_equal; + const duk_uint8_t *src_end; + + src_end = src + srclen; + t = 0; + group_idx = 0; + n_equal = 0; + + while (src < src_end) { + x = *src++; + + if (x >= 'A' && x <= 'Z') { + y = x - 'A' + 0; + } else if (x >= 'a' && x <= 'z') { + y = x - 'a' + 26; + } else if (x >= '0' && x <= '9') { + y = x - '0' + 52; + } else if (x == '+') { + y = 62; + } else if (x == '/') { + y = 63; + } else if (x == '=') { + /* We don't check the zero padding bytes here right now + * (that they're actually zero). This seems to be common + * behavior for base-64 decoders. + */ + + n_equal++; + t <<= 6; /* shift in zeroes */ + goto skip_add; + } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) { + /* allow basic ASCII whitespace */ + continue; + } else { + goto error; + } + + if (n_equal > 0) { + /* Don't allow mixed padding and actual chars. */ + goto error; + } + t = (t << 6) + y; + skip_add: + + if (group_idx == 3) { + /* output 3 bytes from 't' */ + *dst++ = (duk_uint8_t) ((t >> 16) & 0xff); + *dst++ = (duk_uint8_t) ((t >> 8) & 0xff); + *dst++ = (duk_uint8_t) (t & 0xff); + + if (DUK_UNLIKELY(n_equal > 0)) { + /* Backtrack. */ + DUK_ASSERT(n_equal <= 4); + if (n_equal == 1) { + dst -= 1; + } else if (n_equal == 2) { + dst -= 2; + } else { + goto error; /* invalid padding */ + } + + /* Here we can choose either to end parsing and ignore + * whatever follows, or to continue parsing in case + * multiple (possibly padded) base64 strings have been + * concatenated. Currently, keep on parsing. + */ + n_equal = 0; + } + + t = 0; + group_idx = 0; + } else { + group_idx++; + } + } + + if (group_idx != 0) { + /* Here we'd have the option of decoding unpadded base64 + * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not + * accepted. + */ + goto error; + } + + *out_dst_final = dst; + return 1; + + error: + return 0; +} +#endif /* DUK_USE_BASE64_FASTPATH */ + +DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + const duk_uint8_t *src; + duk_size_t srclen; + duk_size_t dstlen; + duk_uint8_t *dst; + const char *ret; + + DUK_ASSERT_CTX_VALID(ctx); + + /* XXX: optimize for string inputs: no need to coerce to a buffer + * which makes a copy of the input. + */ + + index = duk_require_normalize_index(ctx, index); + src = duk__prep_codec_arg(ctx, index, &srclen); + /* Note: for srclen=0, src may be NULL */ + + /* Computation must not wrap; this limit works for 32-bit size_t: + * >>> srclen = 3221225469 + * >>> '%x' % ((srclen + 2) / 3 * 4) + * 'fffffffc' + */ + if (srclen > 3221225469UL) { + goto type_error; + } + dstlen = (srclen + 2) / 3 * 4; + dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen); + + duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst); + + ret = duk_to_string(ctx, -1); + duk_replace(ctx, index); + return ret; + + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED); + return NULL; /* never here */ +} + +DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + const duk_uint8_t *src; + duk_size_t srclen; + duk_size_t dstlen; + duk_uint8_t *dst; + duk_uint8_t *dst_final; + duk_bool_t retval; + + DUK_ASSERT_CTX_VALID(ctx); + + /* XXX: optimize for buffer inputs: no need to coerce to a string + * which causes an unnecessary interning. + */ + + index = duk_require_normalize_index(ctx, index); + src = duk__prep_codec_arg(ctx, index, &srclen); + + /* Computation must not wrap, only srclen + 3 is at risk of + * wrapping because after that the number gets smaller. + * This limit works for 32-bit size_t: + * 0x100000000 - 3 - 1 = 4294967292 + */ + if (srclen > 4294967292UL) { + goto type_error; + } + dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */ + dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen); + /* Note: for dstlen=0, dst may be NULL */ + + retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final); + if (!retval) { + goto type_error; + } + + /* XXX: convert to fixed buffer? */ + (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst)); + duk_replace(ctx, index); + return; + + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); +} + +DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) { + const duk_uint8_t *inp; + duk_size_t len; + duk_size_t i; + duk_uint8_t *buf; + const char *ret; +#if defined(DUK_USE_HEX_FASTPATH) + duk_size_t len_safe; + duk_uint16_t *p16; +#endif + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + inp = duk__prep_codec_arg(ctx, index, &len); + DUK_ASSERT(inp != NULL || len == 0); + + /* Fixed buffer, no zeroing because we'll fill all the data. */ + buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/); + DUK_ASSERT(buf != NULL); + +#if defined(DUK_USE_HEX_FASTPATH) + DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */ + p16 = (duk_uint16_t *) (void *) buf; + len_safe = len & ~0x03U; + for (i = 0; i < len_safe; i += 4) { + p16[0] = duk_hex_enctab[inp[i]]; + p16[1] = duk_hex_enctab[inp[i + 1]]; + p16[2] = duk_hex_enctab[inp[i + 2]]; + p16[3] = duk_hex_enctab[inp[i + 3]]; + p16 += 4; + } + for (; i < len; i++) { + *p16++ = duk_hex_enctab[inp[i]]; + } +#else /* DUK_USE_HEX_FASTPATH */ + for (i = 0; i < len; i++) { + duk_small_uint_t t; + t = (duk_small_uint_t) inp[i]; + buf[i*2 + 0] = duk_lc_digits[t >> 4]; + buf[i*2 + 1] = duk_lc_digits[t & 0x0f]; + } +#endif /* DUK_USE_HEX_FASTPATH */ + + /* XXX: Using a string return value forces a string intern which is + * not always necessary. As a rough performance measure, hex encode + * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s + * without string coercion. Change to returning a buffer and let the + * caller coerce to string if necessary? + */ + + ret = duk_to_string(ctx, -1); + duk_replace(ctx, index); + return ret; +} + +DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) { + duk_hthread *thr = (duk_hthread *) ctx; + const duk_uint8_t *inp; + duk_size_t len; + duk_size_t i; + duk_int_t t; + duk_uint8_t *buf; +#if defined(DUK_USE_HEX_FASTPATH) + duk_int_t chk; + duk_uint8_t *p; + duk_size_t len_safe; +#endif + + DUK_ASSERT_CTX_VALID(ctx); + + index = duk_require_normalize_index(ctx, index); + inp = duk__prep_codec_arg(ctx, index, &len); + DUK_ASSERT(inp != NULL || len == 0); + + if (len & 0x01) { + goto type_error; + } + + /* Fixed buffer, no zeroing because we'll fill all the data. */ + buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/); + DUK_ASSERT(buf != NULL); + +#if defined(DUK_USE_HEX_FASTPATH) + p = buf; + len_safe = len & ~0x07U; + for (i = 0; i < len_safe; i += 8) { + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + chk = t; + p[0] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 3]]); + chk |= t; + p[1] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 5]]); + chk |= t; + p[2] = (duk_uint8_t) t; + t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) | + ((duk_int_t) duk_hex_dectab[inp[i + 7]]); + chk |= t; + p[3] = (duk_uint8_t) t; + p += 4; + + /* Check if any lookup above had a negative result. */ + if (DUK_UNLIKELY(chk < 0)) { + goto type_error; + } + } + for (; i < len; i += 2) { + t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + if (DUK_UNLIKELY(t < 0)) { + goto type_error; + } + *p++ = (duk_uint8_t) t; + } +#else /* DUK_USE_HEX_FASTPATH */ + for (i = 0; i < len; i += 2) { + /* For invalid characters the value -1 gets extended to + * at least 16 bits. If either nybble is invalid, the + * resulting 't' will be < 0. + */ + t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) | + ((duk_int_t) duk_hex_dectab[inp[i + 1]]); + if (DUK_UNLIKELY(t < 0)) { + goto type_error; + } + buf[i >> 1] = (duk_uint8_t) t; + } +#endif /* DUK_USE_HEX_FASTPATH */ + + duk_replace(ctx, index); + return; + + type_error: + DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED); +} + +DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) { +#ifdef DUK_USE_ASSERTIONS + duk_idx_t top_at_entry; +#endif + const char *ret; + + DUK_ASSERT_CTX_VALID(ctx); +#ifdef DUK_USE_ASSERTIONS + top_at_entry = duk_get_top(ctx); +#endif + + index = duk_require_normalize_index(ctx, index); + duk_bi_json_stringify_helper(ctx, + index /*idx_value*/, + DUK_INVALID_INDEX /*idx_replacer*/, + DUK_INVALID_INDEX /*idx_space*/, + 0 /*flags*/); + DUK_ASSERT(duk_is_string(ctx, -1)); + duk_replace(ctx, index); + ret = duk_get_string(ctx, index); + + DUK_ASSERT(duk_get_top(ctx) == top_at_entry); + + return ret; +} + +DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) { +#ifdef DUK_USE_ASSERTIONS + duk_idx_t top_at_entry; +#endif + + DUK_ASSERT_CTX_VALID(ctx); +#ifdef DUK_USE_ASSERTIONS + top_at_entry = duk_get_top(ctx); +#endif + + index = duk_require_normalize_index(ctx, index); + duk_bi_json_parse_helper(ctx, + index /*idx_value*/, + DUK_INVALID_INDEX /*idx_reviver*/, + 0 /*flags*/); + duk_replace(ctx, index); + + DUK_ASSERT(duk_get_top(ctx) == top_at_entry); +}