diff --git a/package/ctcgfw/duktape/Makefile b/package/ctcgfw/duktape/Makefile index 60ee606fa0..8e2896db64 100644 --- a/package/ctcgfw/duktape/Makefile +++ b/package/ctcgfw/duktape/Makefile @@ -7,21 +7,23 @@ include $(TOPDIR)/rules.mk PKG_NAME:=duktape -PKG_VERSION:=2.99.99-65f1e02 +PKG_VERSION:=2.99.99-19cc8f5 PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/svaarala/duktape.git -PKG_SOURCE_VERSION:=65f1e02e580796929e92e91ba4776d4b0131beb5 +PKG_SOURCE_VERSION:=19cc8f5bb855791ff55cbf60d2cea72df485e86f PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz -PKG_LICENSE:=GPLv3 +PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE PKG_MAINTAINER:=CN_SZTL PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) +PKG_BUILD_DEPENDS:=node/host + PKG_FIXUP:=autoreconf PKG_USE_MIPS16:=0 PKG_BUILD_PARALLEL:=1 @@ -40,7 +42,6 @@ define Package/libduktape SECTION:=lib CATEGORY:=Libraries TITLE+= (Libraries) - VARIANT:=lib endef define Package/duktape/description @@ -56,6 +57,9 @@ endef define Build/Compile ( \ cd $(PKG_BUILD_DIR); \ + make -C src-tools; \ + mkdir -p dist; \ + node src-tools/index.js dist --output-directory dist/source; \ cd dist/source/src; \ $(TARGET_CC) -c -O3 -o duktape.o duktape.c; \ $(TARGET_CC) -c -O3 -o duk_module_node.o -I. ../extras/module-node/duk_module_node.c; \ @@ -83,4 +87,4 @@ define Package/libduktape/install endef $(eval $(call BuildPackage,duktape)) -$(eval $(call BuildPackage,libduktape)) +$(eval $(call BuildPackage,libduktape)) \ No newline at end of file diff --git a/package/ctcgfw/duktape/patches/0001-Makefile-use-Node.js-tool-to-generate-files.patch b/package/ctcgfw/duktape/patches/0001-Makefile-use-Node.js-tool-to-generate-files.patch new file mode 100644 index 0000000000..a268dbd285 --- /dev/null +++ b/package/ctcgfw/duktape/patches/0001-Makefile-use-Node.js-tool-to-generate-files.patch @@ -0,0 +1,89 @@ +From 436c0a70d7fd4628f30b860f9f2f18f65982d72d Mon Sep 17 00:00:00 2001 +From: CN_SZTL +Date: Wed, 12 Aug 2020 08:31:27 +0000 +Subject: [PATCH] Makefile: use Node.js tool to generate files + +--- + Makefile | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/Makefile b/Makefile +index 92ec2110..9eba5234 100644 +--- a/Makefile ++++ b/Makefile +@@ -283,55 +283,55 @@ prep: + @mkdir -p prep + prep/nondebug: prep + @rm -rf ./prep/nondebug +- $(PYTHON) tools/configure.py --output-directory ./prep/nondebug --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/nondebug --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG) --line-directives + prep/nondebug-scanbuild: prep + @rm -rf ./prep/nondebug-scanbuild +- $(PYTHON) tools/configure.py --output-directory ./prep/nondebug-scanbuild --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_SCANBUILD) --separate-sources --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/nondebug-scanbuild --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_SCANBUILD) --separate-sources --line-directives + prep/nondebug-perf: prep + @rm -rf ./prep/nondebug-perf +- $(PYTHON) tools/configure.py --output-directory ./prep/nondebug-perf --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_PERF) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/nondebug-perf --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_PERF) --line-directives + prep/nondebug-size: prep + @rm -rf ./prep/nondebug-size +- $(PYTHON) tools/configure.py --output-directory ./prep/nondebug-size --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_SIZE) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/nondebug-size --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_SIZE) --line-directives + prep/nondebug-rom: prep + @rm -rf ./prep/nondebug-rom +- $(PYTHON) tools/configure.py --output-directory ./prep/nondebug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_ROM) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/nondebug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_ROM) --line-directives + prep/debug: prep + @rm -rf ./prep/debug +- $(PYTHON) tools/configure.py --output-directory ./prep/debug --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/debug --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG) --line-directives + prep/fuzz: prep + @rm -rf ./prep/fuzz +- $(PYTHON) tools/configure.py --output-directory ./prep/fuzz --source-directory src-input --config-metadata config $(CONFIGOPTS_FUZZ) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/fuzz --source-directory src-input --config-metadata config $(CONFIGOPTS_FUZZ) --line-directives + prep/debug-scanbuild: prep + @rm -rf ./prep/debug-scanbuild +- $(PYTHON) tools/configure.py --output-directory ./prep/debug-scanbuild --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_SCANBUILD) --separate-sources --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/debug-scanbuild --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_SCANBUILD) --separate-sources --line-directives + prep/debug-rom: prep + @rm -rf ./prep/debug-rom +- $(PYTHON) tools/configure.py --output-directory ./prep/debug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_ROM) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/debug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_ROM) --line-directives + prep/emduk: prep + @rm -rf ./prep/emduk +- $(PYTHON) tools/configure.py --output-directory ./prep/emduk --source-directory src-input --config-metadata config $(CONFIGOPTS_EMDUK) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/emduk --source-directory src-input --config-metadata config $(CONFIGOPTS_EMDUK) --line-directives + prep/dukweb: prep + @rm -rf ./prep/dukweb +- $(PYTHON) tools/configure.py --output-directory ./prep/dukweb --source-directory src-input --config-metadata config $(CONFIGOPTS_DUKWEB) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/dukweb --source-directory src-input --config-metadata config $(CONFIGOPTS_DUKWEB) --line-directives + prep/duklow-nondebug: prep + @rm -rf ./prep/duklow-nondebug +- $(PYTHON) tools/configure.py --output-directory ./prep/duklow-nondebug --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_DUKLOW) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/duklow-nondebug --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_DUKLOW) --line-directives + prep/duklow-debug: prep + @rm -rf ./prep/duklow-debug +- $(PYTHON) tools/configure.py --output-directory ./prep/duklow-debug --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_DUKLOW) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/duklow-debug --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_DUKLOW) --line-directives + prep/duklow-nondebug-rom: prep + @rm -rf ./prep/duklow-nondebug-rom +- $(PYTHON) tools/configure.py --output-directory ./prep/duklow-nondebug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_DUKLOW_ROM) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/duklow-nondebug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_DUKLOW_ROM) --line-directives + prep/duklow-debug-rom: prep + @rm -rf ./prep/duklow-debug-rom +- $(PYTHON) tools/configure.py --output-directory ./prep/duklow-debug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_DUKLOW_ROM) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/duklow-debug-rom --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_DUKLOW_ROM) --line-directives + prep/duklow-nondebug-norefc: prep + @rm -rf ./prep/duklow-nondebug-norefc +- $(PYTHON) tools/configure.py --output-directory ./prep/duklow-nondebug-norefc --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_DUKLOW_NOREFC) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/duklow-nondebug-norefc --source-directory src-input --config-metadata config $(CONFIGOPTS_NONDEBUG_DUKLOW_NOREFC) --line-directives + prep/duklow-debug-norefc: prep + @rm -rf ./prep/duklow-debug-norefc +- $(PYTHON) tools/configure.py --output-directory ./prep/duklow-debug-norefc --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_DUKLOW_NOREFC) --line-directives ++ $(NODE) src-tools/index.js configure --output-directory ./prep/duklow-debug-norefc --source-directory src-input --config-metadata config $(CONFIGOPTS_DEBUG_DUKLOW_NOREFC) --line-directives + + # Library targets. + build/libduktape.so.1.0.0: prep/nondebug | build +-- +2.17.1 + diff --git a/package/ctcgfw/duktape/patches/0001-add-prepared-files.patch b/package/ctcgfw/duktape/patches/0001-add-prepared-files.patch deleted file mode 100644 index 753a147a29..0000000000 --- a/package/ctcgfw/duktape/patches/0001-add-prepared-files.patch +++ /dev/null @@ -1,396802 +0,0 @@ -From 33aa594b6882bbe740f1878507b583b9f65e11f1 Mon Sep 17 00:00:00 2001 -From: CN_SZTL -Date: Wed, 8 Jul 2020 03:09:48 +0000 -Subject: [PATCH] add prepared files - ---- - dist/source/AUTHORS.rst | 115 + - dist/source/LICENSE.txt | 25 + - dist/source/Makefile.cmdline | 47 + - dist/source/Makefile.codepage | 6 + - dist/source/Makefile.coffee | 4 + - dist/source/Makefile.dukdebug | 41 + - dist/source/Makefile.eval | 9 + - dist/source/Makefile.eventloop | 23 + - dist/source/Makefile.hello | 32 + - dist/source/Makefile.jsoncbor | 10 + - dist/source/Makefile.jxpretty | 10 + - dist/source/Makefile.sandbox | 9 + - dist/source/Makefile.sharedlibrary | 88 + - dist/source/README.rst | 129 + - dist/source/config/README.rst | 19 + - dist/source/config/architectures.yaml | 71 + - .../architectures/architecture_arm32.h.in | 3 + - .../architectures/architecture_arm64.h.in | 3 + - .../architecture_emscripten.h.in | 5 + - .../architectures/architecture_generic.h.in | 3 + - .../architectures/architecture_m68k.h.in | 5 + - .../architectures/architecture_mips32.h.in | 3 + - .../architectures/architecture_mips64.h.in | 3 + - .../architectures/architecture_powerpc32.h.in | 5 + - .../architectures/architecture_powerpc64.h.in | 3 + - .../architectures/architecture_riscv32.h.in | 3 + - .../architectures/architecture_riscv64.h.in | 3 + - .../architectures/architecture_sparc32.h.in | 3 + - .../architectures/architecture_sparc64.h.in | 3 + - .../architectures/architecture_superh.h.in | 3 + - .../architectures/architecture_x32.h.in | 5 + - .../architectures/architecture_x64.h.in | 5 + - .../architectures/architecture_x86.h.in | 14 + - dist/source/config/compilers.yaml | 35 + - .../source/config/compilers/compiler_bcc.h.in | 24 + - .../config/compilers/compiler_clang.h.in | 76 + - .../config/compilers/compiler_emscripten.h.in | 45 + - .../source/config/compilers/compiler_gcc.h.in | 99 + - .../config/compilers/compiler_generic.h.in | 24 + - .../config/compilers/compiler_msvc.h.in | 84 + - .../config/compilers/compiler_tinyc.h.in | 18 + - .../config/compilers/compiler_vbcc.h.in | 23 + - .../config-options/DUK_USE_32BIT_PTRS.yaml | 8 + - .../config-options/DUK_USE_64BIT_OPS.yaml | 9 + - .../config-options/DUK_USE_ALIGN_4.yaml | 11 + - .../config-options/DUK_USE_ALIGN_8.yaml | 11 + - .../config-options/DUK_USE_ALIGN_BY.yaml | 8 + - .../DUK_USE_ALLOW_UNDEFINED_BEHAVIOR.yaml | 10 + - .../config-options/DUK_USE_ARCH_STRING.yaml | 9 + - .../config-options/DUK_USE_ARRAY_BUILTIN.yaml | 7 + - .../DUK_USE_ARRAY_FASTPATH.yaml | 15 + - .../DUK_USE_ARRAY_PROP_FASTPATH.yaml | 14 + - .../config-options/DUK_USE_ASSERTIONS.yaml | 9 + - .../DUK_USE_ATAN2_WORKAROUNDS.yaml | 8 + - .../DUK_USE_AUGMENT_ERROR_CREATE.yaml | 8 + - .../DUK_USE_AUGMENT_ERROR_THROW.yaml | 8 + - .../DUK_USE_AVOID_PLATFORM_FUNCPTRS.yaml | 13 + - .../DUK_USE_BASE64_FASTPATH.yaml | 10 + - .../DUK_USE_BASE64_SUPPORT.yaml | 7 + - .../DUK_USE_BOOLEAN_BUILTIN.yaml | 7 + - .../config-options/DUK_USE_BRANCH_HINTS.yaml | 9 + - .../config-options/DUK_USE_BROWSER_LIKE.yaml | 8 + - .../DUK_USE_BUFFEROBJECT_SUPPORT.yaml | 15 + - .../config-options/DUK_USE_BUFLEN16.yaml | 8 + - .../DUK_USE_BUILTIN_INITJS.yaml | 12 + - .../DUK_USE_BYTECODE_DUMP_SUPPORT.yaml | 7 + - .../config-options/DUK_USE_BYTEORDER.yaml | 16 + - .../DUK_USE_BYTEORDER_FORCED.yaml | 9 + - .../DUK_USE_CACHE_ACTIVATION.yaml | 9 + - .../config-options/DUK_USE_CACHE_CATCHER.yaml | 9 + - .../DUK_USE_CALLSTACK_LIMIT.yaml | 10 + - .../config-options/DUK_USE_CBOR_BUILTIN.yaml | 9 + - .../DUK_USE_CBOR_DEC_RECLIMIT.yaml | 8 + - .../DUK_USE_CBOR_ENC_RECLIMIT.yaml | 8 + - .../config-options/DUK_USE_CBOR_SUPPORT.yaml | 10 + - .../config-options/DUK_USE_CLANG_PRAGMAS.yaml | 8 + - .../DUK_USE_COMMONJS_MODULES.yaml | 11 + - .../DUK_USE_COMPILER_RECLIMIT.yaml | 8 + - .../DUK_USE_COMPILER_STRING.yaml | 9 + - .../DUK_USE_COMPUTED_INFINITY.yaml | 15 + - .../config-options/DUK_USE_COMPUTED_NAN.yaml | 15 + - .../DUK_USE_COROUTINE_SUPPORT.yaml | 7 + - .../DUK_USE_CPP_EXCEPTIONS.yaml | 9 + - .../config-options/DUK_USE_DATAPTR16.yaml | 21 + - .../config-options/DUK_USE_DATAPTR_DEC16.yaml | 13 + - .../config-options/DUK_USE_DATAPTR_ENC16.yaml | 15 + - .../config-options/DUK_USE_DATE_BUILTIN.yaml | 7 + - .../DUK_USE_DATE_FMT_STRFTIME.yaml | 10 + - .../DUK_USE_DATE_FORMAT_STRING.yaml | 9 + - .../DUK_USE_DATE_GET_LOCAL_TZOFFSET.yaml | 9 + - .../config-options/DUK_USE_DATE_GET_NOW.yaml | 15 + - .../DUK_USE_DATE_NOW_GETTIMEOFDAY.yaml | 9 + - .../config-options/DUK_USE_DATE_NOW_TIME.yaml | 10 + - .../DUK_USE_DATE_NOW_WINDOWS.yaml | 8 + - .../DUK_USE_DATE_NOW_WINDOWS_SUBMS.yaml | 9 + - .../DUK_USE_DATE_PARSE_STRING.yaml | 9 + - .../DUK_USE_DATE_PRS_GETDATE.yaml | 11 + - .../DUK_USE_DATE_PRS_STRPTIME.yaml | 9 + - .../DUK_USE_DATE_TZO_GMTIME.yaml | 11 + - .../DUK_USE_DATE_TZO_GMTIME_R.yaml | 9 + - .../DUK_USE_DATE_TZO_GMTIME_S.yaml | 8 + - .../DUK_USE_DATE_TZO_WINDOWS.yaml | 8 + - .../DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml | 9 + - .../config-options/DUK_USE_DDDPRINT.yaml | 9 + - .../config-options/DUK_USE_DDPRINT.yaml | 8 + - .../config/config-options/DUK_USE_DEBUG.yaml | 9 + - .../DUK_USE_DEBUGGER_DUMPHEAP.yaml | 12 + - .../DUK_USE_DEBUGGER_FWD_LOGGING.yaml | 14 + - .../DUK_USE_DEBUGGER_FWD_PRINTALERT.yaml | 12 + - .../DUK_USE_DEBUGGER_INSPECT.yaml | 13 + - .../DUK_USE_DEBUGGER_PAUSE_UNCAUGHT.yaml | 17 + - .../DUK_USE_DEBUGGER_SUPPORT.yaml | 13 + - .../DUK_USE_DEBUGGER_THROW_NOTIFY.yaml | 14 + - .../DUK_USE_DEBUGGER_TRANSPORT_TORTURE.yaml | 14 + - .../config-options/DUK_USE_DEBUG_BUFSIZE.yaml | 12 + - .../config-options/DUK_USE_DEBUG_LEVEL.yaml | 8 + - .../config-options/DUK_USE_DEBUG_WRITE.yaml | 16 + - .../config-options/DUK_USE_DEEP_C_STACK.yaml | 12 + - .../config-options/DUK_USE_DOUBLE_BE.yaml | 11 + - .../config-options/DUK_USE_DOUBLE_LE.yaml | 11 + - .../DUK_USE_DOUBLE_LINKED_HEAP.yaml | 11 + - .../config-options/DUK_USE_DOUBLE_ME.yaml | 13 + - .../config/config-options/DUK_USE_DPRINT.yaml | 10 + - .../config-options/DUK_USE_DPRINT_COLORS.yaml | 10 + - .../config-options/DUK_USE_DPRINT_RDTSC.yaml | 8 + - .../DUK_USE_DUKTAPE_BUILTIN.yaml | 7 + - .../DUK_USE_ENCODING_BUILTINS.yaml | 13 + - .../config-options/DUK_USE_ERRCREATE.yaml | 8 + - .../config-options/DUK_USE_ERRTHROW.yaml | 8 + - .../config/config-options/DUK_USE_ES6.yaml | 7 + - .../DUK_USE_ES6_OBJECT_PROTO_PROPERTY.yaml | 7 + - .../DUK_USE_ES6_OBJECT_SETPROTOTYPEOF.yaml | 7 + - .../config-options/DUK_USE_ES6_PROXY.yaml | 7 + - .../DUK_USE_ES6_REGEXP_BRACES.yaml | 8 + - .../DUK_USE_ES6_REGEXP_SYNTAX.yaml | 14 + - .../DUK_USE_ES6_UNICODE_ESCAPE.yaml | 8 + - .../config/config-options/DUK_USE_ES7.yaml | 7 + - .../DUK_USE_ES7_EXP_OPERATOR.yaml | 9 + - .../config/config-options/DUK_USE_ES8.yaml | 7 + - .../config/config-options/DUK_USE_ES9.yaml | 7 + - .../config-options/DUK_USE_ESBC_LIMITS.yaml | 7 + - .../DUK_USE_ESBC_MAX_BYTES.yaml | 9 + - .../DUK_USE_ESBC_MAX_LINENUMBER.yaml | 9 + - .../config-options/DUK_USE_EXAMPLE.yaml | 74 + - .../DUK_USE_EXEC_FUN_LOCAL.yaml | 14 + - .../DUK_USE_EXEC_INDIRECT_BOUND_CHECK.yaml | 11 + - .../DUK_USE_EXEC_PREFER_SIZE.yaml | 7 + - .../DUK_USE_EXEC_REGCONST_OPTIMIZE.yaml | 11 + - .../DUK_USE_EXEC_TIMEOUT_CHECK.yaml | 31 + - .../DUK_USE_EXPLICIT_NULL_INIT.yaml | 12 + - .../config-options/DUK_USE_EXTSTR_FREE.yaml | 23 + - .../DUK_USE_EXTSTR_INTERN_CHECK.yaml | 39 + - .../config-options/DUK_USE_FASTINT.yaml | 14 + - .../DUK_USE_FAST_REFCOUNT_DEFAULT.yaml | 10 + - .../config-options/DUK_USE_FATAL_HANDLER.yaml | 23 + - .../config-options/DUK_USE_FATAL_MAXLEN.yaml | 8 + - .../config-options/DUK_USE_FILE_IO.yaml | 10 + - .../DUK_USE_FINALIZER_SUPPORT.yaml | 7 + - .../DUK_USE_FINALIZER_TORTURE.yaml | 11 + - .../config-options/DUK_USE_FLEX_C99.yaml | 9 + - .../config-options/DUK_USE_FLEX_ONESIZE.yaml | 11 + - .../config-options/DUK_USE_FLEX_ZEROSIZE.yaml | 11 + - .../config-options/DUK_USE_FULL_TVAL.yaml | 16 + - .../config-options/DUK_USE_FUNCPTR16.yaml | 21 + - .../config-options/DUK_USE_FUNCPTR_DEC16.yaml | 15 + - .../config-options/DUK_USE_FUNCPTR_ENC16.yaml | 13 + - .../DUK_USE_FUNCTION_BUILTIN.yaml | 7 + - .../DUK_USE_FUNC_FILENAME_PROPERTY.yaml | 9 + - .../DUK_USE_FUNC_NAME_PROPERTY.yaml | 10 + - .../config-options/DUK_USE_FUZZILLI.yaml | 8 + - .../config-options/DUK_USE_GCC_PRAGMAS.yaml | 8 + - .../config-options/DUK_USE_GC_TORTURE.yaml | 14 + - .../DUK_USE_GET_MONOTONIC_TIME.yaml | 22 + - ..._USE_GET_MONOTONIC_TIME_CLOCK_GETTIME.yaml | 8 + - ...UK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC.yaml | 7 + - .../DUK_USE_GET_RANDOM_DOUBLE.yaml | 16 + - .../DUK_USE_GLOBAL_BINDING.yaml | 8 + - .../DUK_USE_GLOBAL_BUILTIN.yaml | 9 + - ...UK_USE_HASHBYTES_UNALIGNED_U32_ACCESS.yaml | 8 + - .../config-options/DUK_USE_HEAPPTR16.yaml | 35 + - .../config-options/DUK_USE_HEAPPTR_DEC16.yaml | 13 + - .../config-options/DUK_USE_HEAPPTR_ENC16.yaml | 13 + - .../config-options/DUK_USE_HEX_FASTPATH.yaml | 10 + - .../config-options/DUK_USE_HEX_SUPPORT.yaml | 7 + - .../DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml | 15 + - ...DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE.yaml | 11 + - ...K_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml | 13 + - .../DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml | 8 + - ...DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml | 8 + - .../DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml | 8 + - ...DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml | 8 + - .../DUK_USE_HOBJECT_HASH_PART.yaml | 11 + - .../DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml | 20 + - .../DUK_USE_HOBJECT_LAYOUT_1.yaml | 10 + - .../DUK_USE_HOBJECT_LAYOUT_2.yaml | 8 + - .../DUK_USE_HOBJECT_LAYOUT_3.yaml | 9 + - .../DUK_USE_HSTRING_ARRIDX.yaml | 12 + - .../config-options/DUK_USE_HSTRING_CLEN.yaml | 13 + - .../DUK_USE_HSTRING_EXTDATA.yaml | 12 + - .../DUK_USE_HSTRING_LAZY_CLEN.yaml | 11 + - .../config-options/DUK_USE_HTML_COMMENTS.yaml | 7 + - .../DUK_USE_IDCHAR_FASTPATH.yaml | 10 + - .../DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml | 7 + - .../config-options/DUK_USE_INTEGER_BE.yaml | 11 + - .../config-options/DUK_USE_INTEGER_LE.yaml | 11 + - .../config-options/DUK_USE_INTEGER_ME.yaml | 14 + - .../DUK_USE_INTERRUPT_COUNTER.yaml | 13 + - .../DUK_USE_INTERRUPT_DEBUG_FIXUP.yaml | 10 + - .../config/config-options/DUK_USE_JC.yaml | 7 + - .../config-options/DUK_USE_JSON_BUILTIN.yaml | 7 + - .../DUK_USE_JSON_DECNUMBER_FASTPATH.yaml | 10 + - .../DUK_USE_JSON_DECSTRING_FASTPATH.yaml | 10 + - .../DUK_USE_JSON_DEC_RECLIMIT.yaml | 8 + - .../DUK_USE_JSON_EATWHITE_FASTPATH.yaml | 10 + - .../DUK_USE_JSON_ENC_RECLIMIT.yaml | 11 + - .../DUK_USE_JSON_QUOTESTRING_FASTPATH.yaml | 10 + - .../DUK_USE_JSON_STRINGIFY_FASTPATH.yaml | 15 + - .../config-options/DUK_USE_JSON_SUPPORT.yaml | 10 + - .../config/config-options/DUK_USE_JX.yaml | 7 + - .../DUK_USE_LEXER_SLIDING_WINDOW.yaml | 9 + - .../DUK_USE_LIGHTFUNC_BUILTINS.yaml | 10 + - .../config-options/DUK_USE_LITCACHE_SIZE.yaml | 27 + - ...UK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml | 17 + - .../DUK_USE_MARK_AND_SWEEP.yaml | 19 + - .../DUK_USE_MARK_AND_SWEEP_RECLIMIT.yaml | 10 + - .../config-options/DUK_USE_MATH_BUILTIN.yaml | 7 + - .../config-options/DUK_USE_MATH_FMAX.yaml | 14 + - .../config-options/DUK_USE_MATH_FMIN.yaml | 14 + - .../config-options/DUK_USE_MATH_ROUND.yaml | 15 + - .../DUK_USE_MS_STRINGTABLE_RESIZE.yaml | 13 + - .../DUK_USE_NATIVE_CALL_RECLIMIT.yaml | 12 + - .../DUK_USE_NATIVE_STACK_CHECK.yaml | 22 + - .../DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER.yaml | 11 + - .../DUK_USE_NONSTD_ARRAY_MAP_TRAILER.yaml | 13 + - .../DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml | 15 + - .../DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.yaml | 16 + - .../DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY.yaml | 12 + - .../DUK_USE_NONSTD_FUNC_STMT.yaml | 13 + - .../DUK_USE_NONSTD_GETTER_KEY_ARGUMENT.yaml | 11 + - .../DUK_USE_NONSTD_JSON_ESC_U2028_U2029.yaml | 13 + - .../DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE.yaml | 9 + - .../DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.yaml | 11 + - ..._USE_NONSTD_STRING_FROMCHARCODE_32BIT.yaml | 12 + - .../DUK_USE_NO_DOUBLE_ALIASING_SELFTEST.yaml | 12 + - .../DUK_USE_NUMBER_BUILTIN.yaml | 7 + - .../DUK_USE_OBJECT_BUILTIN.yaml | 7 + - .../config-options/DUK_USE_OBJSIZES16.yaml | 12 + - .../config-options/DUK_USE_OCTAL_SUPPORT.yaml | 10 + - .../config-options/DUK_USE_OS_STRING.yaml | 9 + - .../config-options/DUK_USE_PACKED_TVAL.yaml | 11 + - .../DUK_USE_PACKED_TVAL_POSSIBLE.yaml | 8 + - .../DUK_USE_PACK_CLANG_ATTR.yaml | 7 + - .../DUK_USE_PACK_DUMMY_MEMBER.yaml | 7 + - .../config-options/DUK_USE_PACK_GCC_ATTR.yaml | 7 + - .../DUK_USE_PACK_MSVC_PRAGMA.yaml | 7 + - .../config-options/DUK_USE_PANIC_ABORT.yaml | 8 + - .../config-options/DUK_USE_PANIC_EXIT.yaml | 8 + - .../config-options/DUK_USE_PANIC_HANDLER.yaml | 11 + - .../DUK_USE_PANIC_SEGFAULT.yaml | 10 + - .../DUK_USE_PARANOID_DATE_COMPUTATION.yaml | 15 + - .../DUK_USE_PARANOID_ERRORS.yaml | 14 + - .../config-options/DUK_USE_PARANOID_MATH.yaml | 8 + - .../config-options/DUK_USE_PC2LINE.yaml | 11 + - .../DUK_USE_PERFORMANCE_BUILTIN.yaml | 7 + - .../DUK_USE_POW_NETBSD_WORKAROUND.yaml | 11 + - .../DUK_USE_POW_WORKAROUNDS.yaml | 9 + - .../config-options/DUK_USE_PREFER_SIZE.yaml | 9 + - .../DUK_USE_PROMISE_BUILTIN.yaml | 9 + - ...K_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS.yaml | 9 + - .../config/config-options/DUK_USE_RDTSC.yaml | 8 + - .../config-options/DUK_USE_REFCOUNT16.yaml | 9 + - .../config-options/DUK_USE_REFCOUNT32.yaml | 12 + - .../DUK_USE_REFERENCE_COUNTING.yaml | 7 + - .../DUK_USE_REFLECT_BUILTIN.yaml | 8 + - .../DUK_USE_REFZERO_FINALIZER_TORTURE.yaml | 15 + - .../DUK_USE_REGEXP_CANON_BITMAP.yaml | 11 + - .../DUK_USE_REGEXP_CANON_WORKAROUND.yaml | 13 + - .../DUK_USE_REGEXP_COMPILER_RECLIMIT.yaml | 8 + - .../DUK_USE_REGEXP_EXECUTOR_RECLIMIT.yaml | 8 + - .../DUK_USE_REGEXP_SUPPORT.yaml | 15 + - .../DUK_USE_REPL_FPCLASSIFY.yaml | 12 + - .../config-options/DUK_USE_REPL_ISFINITE.yaml | 12 + - .../config-options/DUK_USE_REPL_ISINF.yaml | 12 + - .../config-options/DUK_USE_REPL_ISNAN.yaml | 12 + - .../config-options/DUK_USE_REPL_SIGNBIT.yaml | 12 + - .../DUK_USE_ROM_GLOBAL_CLONE.yaml | 18 + - .../DUK_USE_ROM_GLOBAL_INHERIT.yaml | 23 + - .../config-options/DUK_USE_ROM_OBJECTS.yaml | 22 + - .../DUK_USE_ROM_PTRCOMP_FIRST.yaml | 16 + - .../config-options/DUK_USE_ROM_STRINGS.yaml | 13 + - .../config-options/DUK_USE_SECTION_B.yaml | 11 + - .../config-options/DUK_USE_SELF_TESTS.yaml | 9 + - .../config/config-options/DUK_USE_SETJMP.yaml | 17 + - .../DUK_USE_SHEBANG_COMMENTS.yaml | 8 + - .../DUK_USE_SHUFFLE_TORTURE.yaml | 12 + - .../config-options/DUK_USE_SIGSETJMP.yaml | 12 + - .../config-options/DUK_USE_SOURCE_NONBMP.yaml | 11 + - .../config-options/DUK_USE_STRHASH16.yaml | 8 + - .../config-options/DUK_USE_STRHASH_DENSE.yaml | 10 + - .../DUK_USE_STRHASH_SKIP_SHIFT.yaml | 12 + - .../config-options/DUK_USE_STRICT_DECL.yaml | 13 + - .../DUK_USE_STRICT_UTF8_SOURCE.yaml | 11 + - .../DUK_USE_STRING_BUILTIN.yaml | 7 + - .../config-options/DUK_USE_STRLEN16.yaml | 8 + - .../config-options/DUK_USE_STRTAB_CHAIN.yaml | 27 + - .../DUK_USE_STRTAB_CHAIN_SIZE.yaml | 10 + - .../DUK_USE_STRTAB_GROW_LIMIT.yaml | 10 + - .../DUK_USE_STRTAB_MAXSIZE.yaml | 13 + - .../DUK_USE_STRTAB_MINSIZE.yaml | 9 + - .../config-options/DUK_USE_STRTAB_PROBE.yaml | 8 + - .../DUK_USE_STRTAB_PTRCOMP.yaml | 14 + - .../DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml | 16 + - .../DUK_USE_STRTAB_SHRINK_LIMIT.yaml | 10 + - .../DUK_USE_STRTAB_TORTURE.yaml | 9 + - .../DUK_USE_SYMBOL_BUILTIN.yaml | 10 + - .../config-options/DUK_USE_TAILCALL.yaml | 13 + - .../config-options/DUK_USE_TARGET_INFO.yaml | 10 + - .../config-options/DUK_USE_TRACEBACKS.yaml | 12 + - .../DUK_USE_TRACEBACK_DEPTH.yaml | 13 + - .../DUK_USE_UNALIGNED_ACCESSES_POSSIBLE.yaml | 9 + - .../DUK_USE_UNDERSCORE_SETJMP.yaml | 13 + - .../DUK_USE_UNION_INITIALIZERS.yaml | 11 + - .../config-options/DUK_USE_USER_DECLARE.yaml | 17 + - .../config-options/DUK_USE_USER_INITJS.yaml | 13 + - .../DUK_USE_VALSTACK_GROW_SHIFT.yaml | 13 + - .../DUK_USE_VALSTACK_LIMIT.yaml | 11 + - .../DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT.yaml | 13 + - .../DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT.yaml | 10 + - .../DUK_USE_VALSTACK_UNSAFE.yaml | 11 + - .../DUK_USE_VARIADIC_MACROS.yaml | 11 + - .../DUK_USE_VERBOSE_ERRORS.yaml | 11 + - .../DUK_USE_VERBOSE_EXECUTOR_ERRORS.yaml | 10 + - .../config-options/DUK_USE_VOLUNTARY_GC.yaml | 16 + - .../DUK_USE_ZERO_BUFFER_DATA.yaml | 11 + - dist/source/config/examples/compliance.yaml | 18 + - .../config/examples/debugger_support.yaml | 24 + - .../examples/disable_bufferobjects.yaml | 3 + - dist/source/config/examples/disable_es6.yaml | 5 + - .../config/examples/enable_debug_print0.yaml | 3 + - .../config/examples/enable_debug_print1.yaml | 3 + - .../config/examples/enable_debug_print2.yaml | 3 + - .../config/examples/enable_fastint.yaml | 3 + - dist/source/config/examples/low_memory.yaml | 158 + - .../config/examples/low_memory_strip.yaml | 49 + - .../examples/performance_sensitive.yaml | 38 + - dist/source/config/examples/rom_builtins.yaml | 19 + - .../config/examples/security_sensitive.yaml | 17 + - .../config/examples/shallow_c_stack.yaml | 10 + - .../config/examples/timing_sensitive.yaml | 6 + - .../feature-options/DUK_OPT_ASSERTIONS.yaml | 8 + - .../DUK_OPT_BUFFEROBJECT_SUPPORT.yaml | 8 + - .../feature-options/DUK_OPT_BUFLEN16.yaml | 7 + - .../feature-options/DUK_OPT_DATAPTR16.yaml | 20 + - .../DUK_OPT_DATAPTR_DEC16.yaml | 12 + - .../DUK_OPT_DATAPTR_ENC16.yaml | 14 + - .../feature-options/DUK_OPT_DDDPRINT.yaml | 9 + - .../feature-options/DUK_OPT_DDPRINT.yaml | 8 + - .../config/feature-options/DUK_OPT_DEBUG.yaml | 7 + - .../DUK_OPT_DEBUGGER_DUMPHEAP.yaml | 10 + - .../DUK_OPT_DEBUGGER_FWD_LOGGING.yaml | 11 + - .../DUK_OPT_DEBUGGER_FWD_PRINTALERT.yaml | 9 + - .../DUK_OPT_DEBUGGER_SUPPORT.yaml | 12 + - .../DUK_OPT_DEBUGGER_TRANSPORT_TORTURE.yaml | 11 + - .../DUK_OPT_DEBUG_BUFSIZE.yaml | 11 + - .../feature-options/DUK_OPT_DECLARE.yaml | 10 + - .../feature-options/DUK_OPT_DEEP_C_STACK.yaml | 15 + - .../feature-options/DUK_OPT_DLL_BUILD.yaml | 12 + - .../feature-options/DUK_OPT_DPRINT.yaml | 8 + - .../DUK_OPT_DPRINT_COLORS.yaml | 8 + - .../feature-options/DUK_OPT_DPRINT_RDTSC.yaml | 7 + - .../feature-options/DUK_OPT_EXAMPLE.yaml | 52 + - .../DUK_OPT_EXEC_TIMEOUT_CHECK.yaml | 30 + - .../DUK_OPT_EXTERNAL_STRINGS.yaml | 11 + - .../feature-options/DUK_OPT_EXTSTR_FREE.yaml | 22 + - .../DUK_OPT_EXTSTR_INTERN_CHECK.yaml | 38 + - .../feature-options/DUK_OPT_FASTINT.yaml | 10 + - .../feature-options/DUK_OPT_FORCE_ALIGN.yaml | 8 + - .../DUK_OPT_FORCE_BYTEORDER.yaml | 10 + - .../feature-options/DUK_OPT_FUNCPTR16.yaml | 21 + - .../DUK_OPT_FUNCPTR_DEC16.yaml | 12 + - .../DUK_OPT_FUNCPTR_ENC16.yaml | 12 + - .../DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY.yaml | 9 + - .../DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY.yaml | 9 + - .../feature-options/DUK_OPT_GC_TORTURE.yaml | 9 + - .../DUK_OPT_HAVE_CUSTOM_H.yaml | 26 + - .../feature-options/DUK_OPT_HEAPPTR16.yaml | 34 + - .../DUK_OPT_HEAPPTR_DEC16.yaml | 12 + - .../DUK_OPT_HEAPPTR_ENC16.yaml | 12 + - .../DUK_OPT_INTERRUPT_COUNTER.yaml | 12 + - .../DUK_OPT_JSON_STRINGIFY_FASTPATH.yaml | 9 + - .../DUK_OPT_LIGHTFUNC_BUILTINS.yaml | 9 + - .../DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY.yaml | 14 + - .../DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY.yaml | 10 + - ...K_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT.yaml | 9 + - .../DUK_OPT_NO_AUGMENT_ERRORS.yaml | 10 + - .../DUK_OPT_NO_BROWSER_LIKE.yaml | 9 + - .../DUK_OPT_NO_BUFFEROBJECT_SUPPORT.yaml | 8 + - .../DUK_OPT_NO_BYTECODE_DUMP_SUPPORT.yaml | 7 + - .../DUK_OPT_NO_COMMONJS_MODULES.yaml | 6 + - .../DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY.yaml | 8 + - .../DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF.yaml | 8 + - .../feature-options/DUK_OPT_NO_ES6_PROXY.yaml | 8 + - .../feature-options/DUK_OPT_NO_FILE_IO.yaml | 10 + - .../feature-options/DUK_OPT_NO_FUNC_STMT.yaml | 9 + - .../config/feature-options/DUK_OPT_NO_JC.yaml | 7 + - .../feature-options/DUK_OPT_NO_JSONC.yaml | 9 + - .../feature-options/DUK_OPT_NO_JSONX.yaml | 9 + - .../config/feature-options/DUK_OPT_NO_JX.yaml | 7 + - .../DUK_OPT_NO_MARK_AND_SWEEP.yaml | 14 + - .../DUK_OPT_NO_MS_STRINGTABLE_RESIZE.yaml | 9 + - ...K_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT.yaml | 8 + - ...UK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER.yaml | 12 + - .../DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER.yaml | 12 + - ...K_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml | 13 + - .../DUK_OPT_NO_NONSTD_FUNC_STMT.yaml | 10 + - ...UK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029.yaml | 10 + - ...T_NO_NONSTD_STRING_FROMCHARCODE_32BIT.yaml | 9 + - .../DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY.yaml | 10 + - .../DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF.yaml | 10 + - .../DUK_OPT_NO_OCTAL_SUPPORT.yaml | 7 + - .../DUK_OPT_NO_PACKED_TVAL.yaml | 9 + - .../feature-options/DUK_OPT_NO_PC2LINE.yaml | 9 + - .../DUK_OPT_NO_REFERENCE_COUNTING.yaml | 9 + - .../DUK_OPT_NO_REGEXP_SUPPORT.yaml | 11 + - .../feature-options/DUK_OPT_NO_SECTION_B.yaml | 9 + - .../DUK_OPT_NO_SOURCE_NONBMP.yaml | 7 + - .../DUK_OPT_NO_STRICT_DECL.yaml | 8 + - .../DUK_OPT_NO_TRACEBACKS.yaml | 8 + - .../DUK_OPT_NO_VERBOSE_ERRORS.yaml | 8 + - .../DUK_OPT_NO_VOLUNTARY_GC.yaml | 13 + - .../DUK_OPT_NO_ZERO_BUFFER_DATA.yaml | 8 + - .../feature-options/DUK_OPT_OBJSIZES16.yaml | 11 + - .../DUK_OPT_PANIC_HANDLER.yaml | 6 + - .../feature-options/DUK_OPT_REFCOUNT16.yaml | 7 + - .../DUK_OPT_SEGFAULT_ON_PANIC.yaml | 8 + - .../feature-options/DUK_OPT_SELF_TESTS.yaml | 8 + - .../feature-options/DUK_OPT_SETJMP.yaml | 18 + - .../DUK_OPT_SHUFFLE_TORTURE.yaml | 10 + - .../feature-options/DUK_OPT_SIGSETJMP.yaml | 9 + - .../feature-options/DUK_OPT_STRHASH16.yaml | 7 + - .../DUK_OPT_STRICT_UTF8_SOURCE.yaml | 9 + - .../feature-options/DUK_OPT_STRLEN16.yaml | 7 + - .../feature-options/DUK_OPT_STRTAB_CHAIN.yaml | 25 + - .../DUK_OPT_STRTAB_CHAIN_SIZE.yaml | 8 + - .../feature-options/DUK_OPT_TARGET_INFO.yaml | 8 + - .../DUK_OPT_TRACEBACK_DEPTH.yaml | 6 + - .../DUK_OPT_UNDERSCORE_SETJMP.yaml | 10 + - .../feature-options/DUK_OPT_USER_INITJS.yaml | 11 + - .../config/header-snippets/64bitops.h.in | 11 + - .../header-snippets/alignment_fillin.h.in | 26 + - .../header-snippets/architecture_fillins.h.in | 0 - .../header-snippets/byteorder_derived.h.in | 21 + - .../header-snippets/byteorder_fillin.h.in | 109 + - .../header-snippets/compiler_fillins.h.in | 205 + - .../header-snippets/cpp_exception_sanity.h.in | 3 + - .../config/header-snippets/date_provider.h.in | 66 + - .../header-snippets/gcc_clang_visibility.h.in | 26 + - .../header-snippets/inline_workaround.h.in | 11 + - .../header-snippets/msvc_visibility.h.in | 19 + - .../config/header-snippets/object_layout.h.in | 21 + - .../header-snippets/packed_tval_fillin.h.in | 40 + - .../platform_conditionalincludes.h.in | 4 + - .../header-snippets/platform_cppextras.h.in | 9 + - .../header-snippets/platform_fillins.h.in | 327 + - .../platform_sharedincludes.h.in | 24 + - .../header-snippets/reject_fast_math.h.in | 6 + - .../source/config/header-snippets/types1.h.in | 78 + - .../source/config/header-snippets/types2.h.in | 132 + - .../config/header-snippets/types_c99.h.in | 95 + - .../config/header-snippets/types_legacy.h.in | 242 + - .../config/helper-snippets/DUK_F_AIX.h.in | 5 + - .../config/helper-snippets/DUK_F_AMIGAOS.h.in | 6 + - .../config/helper-snippets/DUK_F_ANDROID.h.in | 3 + - .../config/helper-snippets/DUK_F_APPLE.h.in | 4 + - .../config/helper-snippets/DUK_F_ARM.h.in | 9 + - .../config/helper-snippets/DUK_F_BCC.h.in | 4 + - .../config/helper-snippets/DUK_F_BSD.h.in | 5 + - .../config/helper-snippets/DUK_F_C99.h.in | 5 + - .../config/helper-snippets/DUK_F_CLANG.h.in | 4 + - .../config/helper-snippets/DUK_F_CPP.h.in | 5 + - .../config/helper-snippets/DUK_F_CPP11.h.in | 5 + - .../config/helper-snippets/DUK_F_CYGWIN.h.in | 4 + - .../config/helper-snippets/DUK_F_DURANGO.h.in | 4 + - .../helper-snippets/DUK_F_EMSCRIPTEN.h.in | 4 + - .../helper-snippets/DUK_F_FLASHPLAYER.h.in | 4 + - .../config/helper-snippets/DUK_F_FREEBSD.h.in | 4 + - .../config/helper-snippets/DUK_F_GCC.h.in | 10 + - .../config/helper-snippets/DUK_F_HPUX.h.in | 7 + - .../config/helper-snippets/DUK_F_LINUX.h.in | 4 + - .../config/helper-snippets/DUK_F_M68K.h.in | 6 + - .../config/helper-snippets/DUK_F_MINGW.h.in | 4 + - .../config/helper-snippets/DUK_F_MINT.h.in | 4 + - .../config/helper-snippets/DUK_F_MIPS.h.in | 14 + - .../config/helper-snippets/DUK_F_MSVC.h.in | 15 + - .../config/helper-snippets/DUK_F_NETBSD.h.in | 4 + - .../helper-snippets/DUK_F_NO_STDINT_H.h.in | 10 + - .../config/helper-snippets/DUK_F_OPENBSD.h.in | 4 + - .../config/helper-snippets/DUK_F_ORBIS.h.in | 4 + - .../config/helper-snippets/DUK_F_POSIX.h.in | 4 + - .../config/helper-snippets/DUK_F_PPC.h.in | 9 + - .../config/helper-snippets/DUK_F_QNX.h.in | 4 + - .../config/helper-snippets/DUK_F_RISCV.h.in | 15 + - .../config/helper-snippets/DUK_F_SPARC.h.in | 9 + - .../config/helper-snippets/DUK_F_SUN.h.in | 12 + - .../config/helper-snippets/DUK_F_SUPERH.h.in | 9 + - .../helper-snippets/DUK_F_TINSPIRE.h.in | 4 + - .../config/helper-snippets/DUK_F_TINYC.h.in | 5 + - .../config/helper-snippets/DUK_F_TOS.h.in | 6 + - .../config/helper-snippets/DUK_F_UCLIBC.h.in | 4 + - .../helper-snippets/DUK_F_ULL_CONSTS.h.in | 9 + - .../config/helper-snippets/DUK_F_UNIX.h.in | 5 + - .../config/helper-snippets/DUK_F_VBCC.h.in | 4 + - .../config/helper-snippets/DUK_F_WINDOWS.h.in | 10 + - .../config/helper-snippets/DUK_F_X86.h.in | 26 + - dist/source/config/platforms.yaml | 89 + - .../source/config/platforms/platform_aix.h.in | 12 + - .../config/platforms/platform_amigaos.h.in | 26 + - .../config/platforms/platform_android.h.in | 33 + - .../config/platforms/platform_apple.h.in | 49 + - .../config/platforms/platform_cygwin.h.in | 15 + - .../config/platforms/platform_durango.h.in | 32 + - .../config/platforms/platform_emscripten.h.in | 29 + - .../platforms/platform_flashplayer.h.in | 14 + - .../config/platforms/platform_generic.h.in | 18 + - .../config/platforms/platform_genericbsd.h.in | 11 + - .../platforms/platform_genericunix.h.in | 7 + - .../config/platforms/platform_hpux.h.in | 13 + - .../config/platforms/platform_linux.h.in | 33 + - .../config/platforms/platform_openbsd.h.in | 12 + - .../config/platforms/platform_orbis.h.in | 12 + - .../config/platforms/platform_posix.h.in | 11 + - .../source/config/platforms/platform_qnx.h.in | 16 + - .../config/platforms/platform_solaris.h.in | 21 + - .../config/platforms/platform_tinspire.h.in | 14 + - .../source/config/platforms/platform_tos.h.in | 12 + - .../config/platforms/platform_windows.h.in | 59 + - dist/source/config/tags.yaml | 105 + - dist/source/debugger/Makefile | 101 + - dist/source/debugger/README.rst | 385 + - dist/source/debugger/duk_classnames.yaml | 32 + - dist/source/debugger/duk_debug.js | 2491 + - dist/source/debugger/duk_debug_meta.json | 2189 + - dist/source/debugger/duk_debug_proxy.js | 1044 + - dist/source/debugger/duk_debugcommands.yaml | 52 + - dist/source/debugger/duk_debugerrors.yaml | 6 + - dist/source/debugger/duk_opcodes.yaml | 1193 + - dist/source/debugger/package.json | 27 + - dist/source/debugger/static/index.html | 96 + - dist/source/debugger/static/style.css | 517 + - dist/source/debugger/static/webui.js | 808 + - dist/source/duk_dist_meta.json | 9 + - dist/source/examples/README.rst | 10 + - dist/source/examples/alloc-hybrid/README.rst | 10 + - .../examples/alloc-hybrid/duk_alloc_hybrid.c | 294 + - .../examples/alloc-hybrid/duk_alloc_hybrid.h | 11 + - dist/source/examples/alloc-logging/README.rst | 7 + - .../alloc-logging/duk_alloc_logging.c | 139 + - .../alloc-logging/duk_alloc_logging.h | 10 + - .../examples/alloc-logging/log2gnuplot.py | 41 + - dist/source/examples/alloc-torture/README.rst | 10 + - .../alloc-torture/duk_alloc_torture.c | 183 + - .../alloc-torture/duk_alloc_torture.h | 10 + - dist/source/examples/cmdline/README.rst | 6 + - dist/source/examples/cmdline/duk_cmdline.c | 1867 + - dist/source/examples/cmdline/duk_cmdline.h | 16 + - .../examples/cmdline/duk_cmdline_lowmem.c | 1016 + - dist/source/examples/codepage-conv/README.rst | 8 + - .../codepage-conv/duk_codepage_conv.c | 54 + - .../codepage-conv/duk_codepage_conv.h | 8 + - dist/source/examples/codepage-conv/test.c | 298 + - dist/source/examples/coffee/README.rst | 10 + - dist/source/examples/coffee/globals.coffee | 7 + - dist/source/examples/coffee/hello.coffee | 2 + - dist/source/examples/coffee/mandel.coffee | 28 + - .../source/examples/cpp-exceptions/README.rst | 29 + - .../cpp-exceptions/cpp_exceptions.cpp | 311 + - .../examples/debug-trans-dvalue/Makefile | 16 + - .../examples/debug-trans-dvalue/README.rst | 8 + - .../debug-trans-dvalue/duk_trans_dvalue.c | 1241 + - .../debug-trans-dvalue/duk_trans_dvalue.h | 113 + - .../source/examples/debug-trans-dvalue/test.c | 248 + - .../examples/debug-trans-socket/README.rst | 17 + - .../debug-trans-socket/duk_trans_socket.h | 23 + - .../duk_trans_socket_unix.c | 364 + - .../duk_trans_socket_windows.c | 419 + - .../examples/dummy-date-provider/README.rst | 5 + - .../dummy-date-provider/dummy_date_provider.c | 27 + - dist/source/examples/eval/README.rst | 5 + - dist/source/examples/eval/eval.c | 55 + - dist/source/examples/eventloop/README.rst | 72 + - dist/source/examples/eventloop/basic-test.js | 16 + - dist/source/examples/eventloop/c_eventloop.c | 626 + - dist/source/examples/eventloop/c_eventloop.h | 7 + - dist/source/examples/eventloop/c_eventloop.js | 192 + - .../examples/eventloop/client-socket-test.js | 16 + - .../examples/eventloop/ecma_eventloop.js | 478 + - dist/source/examples/eventloop/fileio.c | 84 + - dist/source/examples/eventloop/main.c | 286 + - dist/source/examples/eventloop/poll.c | 119 + - .../examples/eventloop/server-socket-test.js | 33 + - dist/source/examples/eventloop/socket.c | 286 + - dist/source/examples/eventloop/timer-test.js | 40 + - dist/source/examples/guide/README.rst | 5 + - dist/source/examples/guide/fib.js | 16 + - dist/source/examples/guide/prime.js | 32 + - dist/source/examples/guide/primecheck.c | 81 + - dist/source/examples/guide/process.js | 12 + - dist/source/examples/guide/processlines.c | 78 + - dist/source/examples/guide/uppercase.c | 42 + - dist/source/examples/hello/README.rst | 5 + - dist/source/examples/hello/hello.c | 46 + - dist/source/examples/jxpretty/README.rst | 5 + - dist/source/examples/jxpretty/jxpretty.c | 76 + - dist/source/examples/sandbox/README.rst | 5 + - dist/source/examples/sandbox/sandbox.c | 266 + - dist/source/extras/README.rst | 13 + - dist/source/extras/alloc-pool/Makefile | 42 + - dist/source/extras/alloc-pool/README.rst | 38 + - .../source/extras/alloc-pool/duk_alloc_pool.c | 612 + - .../source/extras/alloc-pool/duk_alloc_pool.h | 231 + - dist/source/extras/alloc-pool/ptrcomp.yaml | 16 + - dist/source/extras/alloc-pool/ptrcomp_fixup.h | 2 + - dist/source/extras/alloc-pool/test.c | 114 + - dist/source/extras/cbor/Makefile | 261 + - dist/source/extras/cbor/README.rst | 150 + - dist/source/extras/cbor/cbordecode.py | 24 + - dist/source/extras/cbor/duk_cbor.c | 2075 + - dist/source/extras/cbor/duk_cbor.h | 20 + - dist/source/extras/cbor/jsoncbor.c | 207 + - dist/source/extras/cbor/run_testvectors.js | 30 + - dist/source/extras/console/Makefile | 20 + - dist/source/extras/console/README.rst | 35 + - dist/source/extras/console/duk_console.c | 185 + - dist/source/extras/console/duk_console.h | 29 + - dist/source/extras/console/test.c | 30 + - dist/source/extras/duk-v1-compat/Makefile | 15 + - dist/source/extras/duk-v1-compat/README.rst | 25 + - .../extras/duk-v1-compat/duk_v1_compat.c | 131 + - .../extras/duk-v1-compat/duk_v1_compat.h | 36 + - dist/source/extras/duk-v1-compat/test.c | 104 + - .../extras/duk-v1-compat/test_compile1.js | 3 + - .../extras/duk-v1-compat/test_compile2.js | 3 + - .../source/extras/duk-v1-compat/test_eval1.js | 4 + - .../source/extras/duk-v1-compat/test_eval2.js | 4 + - dist/source/extras/logging/Makefile | 22 + - dist/source/extras/logging/README.rst | 33 + - dist/source/extras/logging/duk_logging.c | 380 + - dist/source/extras/logging/duk_logging.h | 28 + - dist/source/extras/logging/test.c | 56 + - dist/source/extras/minimal-printf/Makefile | 7 + - dist/source/extras/minimal-printf/README.rst | 116 + - .../minimal-printf/duk_minimal_printf.c | 312 + - .../minimal-printf/duk_minimal_printf.h | 20 + - dist/source/extras/minimal-printf/test.c | 190 + - dist/source/extras/module-duktape/Makefile | 23 + - dist/source/extras/module-duktape/README.rst | 31 + - .../module-duktape/duk_module_duktape.c | 471 + - .../module-duktape/duk_module_duktape.h | 22 + - dist/source/extras/module-duktape/test.c | 55 + - dist/source/extras/module-node/Makefile | 28 + - dist/source/extras/module-node/README.rst | 89 + - .../extras/module-node/duk_module_node.c | 333 + - .../extras/module-node/duk_module_node.h | 17 + - dist/source/extras/module-node/test.c | 103 + - dist/source/extras/print-alert/Makefile | 16 + - dist/source/extras/print-alert/README.rst | 27 + - .../extras/print-alert/duk_print_alert.c | 127 + - .../extras/print-alert/duk_print_alert.h | 18 + - dist/source/extras/print-alert/test.c | 30 + - dist/source/licenses/commonjs.txt | 2 + - dist/source/licenses/lua.txt | 1 + - dist/source/licenses/murmurhash2.txt | 21 + - dist/source/licenses/splitmix64.txt | 7 + - dist/source/licenses/xoroshiro128plus.txt | 7 + - dist/source/mandel.js | 53 + - dist/source/polyfills/console-minimal.js | 20 + - dist/source/polyfills/duktape-buffer.js | 53 + - .../duktape-error-setter-nonwritable.js | 20 + - .../duktape-error-setter-writable.js | 19 + - dist/source/polyfills/duktape-isfastint.js | 38 + - dist/source/polyfills/global.js | 15 + - dist/source/polyfills/object-assign.js | 45 + - .../object-prototype-definegetter.js | 14 + - .../object-prototype-definesetter.js | 14 + - dist/source/polyfills/performance-now.js | 25 + - dist/source/polyfills/promise.js | 607 + - dist/source/src-input/SpecialCasing-8bit.txt | 1 + - dist/source/src-input/SpecialCasing.txt | 281 + - dist/source/src-input/UnicodeData-8bit.txt | 256 + - dist/source/src-input/UnicodeData.txt | 32841 +++++ - dist/source/src-input/builtins.yaml | 5539 + - dist/source/src-input/duk_alloc_default.c | 34 + - dist/source/src-input/duk_api_buffer.c | 73 + - dist/source/src-input/duk_api_bytecode.c | 760 + - dist/source/src-input/duk_api_call.c | 516 + - dist/source/src-input/duk_api_codec.c | 926 + - dist/source/src-input/duk_api_compile.c | 172 + - dist/source/src-input/duk_api_debug.c | 261 + - dist/source/src-input/duk_api_heap.c | 211 + - dist/source/src-input/duk_api_inspect.c | 229 + - dist/source/src-input/duk_api_internal.h | 386 + - dist/source/src-input/duk_api_memory.c | 80 + - dist/source/src-input/duk_api_object.c | 1050 + - dist/source/src-input/duk_api_random.c | 9 + - dist/source/src-input/duk_api_stack.c | 6867 ++ - dist/source/src-input/duk_api_string.c | 378 + - dist/source/src-input/duk_api_time.c | 110 + - dist/source/src-input/duk_bi_array.c | 1647 + - dist/source/src-input/duk_bi_boolean.c | 69 + - dist/source/src-input/duk_bi_buffer.c | 2923 + - dist/source/src-input/duk_bi_cbor.c | 1737 + - dist/source/src-input/duk_bi_date.c | 1769 + - dist/source/src-input/duk_bi_date_unix.c | 325 + - dist/source/src-input/duk_bi_date_windows.c | 193 + - dist/source/src-input/duk_bi_duktape.c | 158 + - dist/source/src-input/duk_bi_encoding.c | 533 + - dist/source/src-input/duk_bi_error.c | 387 + - dist/source/src-input/duk_bi_function.c | 453 + - dist/source/src-input/duk_bi_global.c | 727 + - dist/source/src-input/duk_bi_json.c | 3266 + - dist/source/src-input/duk_bi_math.c | 519 + - dist/source/src-input/duk_bi_number.c | 280 + - dist/source/src-input/duk_bi_object.c | 803 + - dist/source/src-input/duk_bi_performance.c | 31 + - dist/source/src-input/duk_bi_pointer.c | 75 + - dist/source/src-input/duk_bi_promise.c | 44 + - dist/source/src-input/duk_bi_protos.h | 81 + - dist/source/src-input/duk_bi_proxy.c | 98 + - dist/source/src-input/duk_bi_reflect.c | 99 + - dist/source/src-input/duk_bi_regexp.c | 226 + - dist/source/src-input/duk_bi_string.c | 1603 + - dist/source/src-input/duk_bi_symbol.c | 170 + - dist/source/src-input/duk_bi_thread.c | 326 + - dist/source/src-input/duk_bi_thrower.c | 9 + - dist/source/src-input/duk_dblunion.h | 424 + - dist/source/src-input/duk_debug.h | 184 + - dist/source/src-input/duk_debug_fixedbuffer.c | 69 + - dist/source/src-input/duk_debug_macros.c | 88 + - dist/source/src-input/duk_debug_vsnprintf.c | 1093 + - dist/source/src-input/duk_debugger.c | 2909 + - dist/source/src-input/duk_debugger.h | 151 + - dist/source/src-input/duk_error.h | 525 + - dist/source/src-input/duk_error_augment.c | 588 + - dist/source/src-input/duk_error_longjmp.c | 103 + - dist/source/src-input/duk_error_macros.c | 152 + - dist/source/src-input/duk_error_misc.c | 181 + - dist/source/src-input/duk_error_throw.c | 162 + - dist/source/src-input/duk_exception.h | 30 + - dist/source/src-input/duk_fltunion.h | 39 + - dist/source/src-input/duk_forwdecl.h | 134 + - dist/source/src-input/duk_harray.h | 48 + - dist/source/src-input/duk_hboundfunc.h | 37 + - dist/source/src-input/duk_hbuffer.h | 336 + - dist/source/src-input/duk_hbuffer_alloc.c | 132 + - dist/source/src-input/duk_hbuffer_assert.c | 13 + - dist/source/src-input/duk_hbuffer_ops.c | 78 + - dist/source/src-input/duk_hbufobj.h | 127 + - dist/source/src-input/duk_hbufobj_misc.c | 20 + - dist/source/src-input/duk_hcompfunc.h | 273 + - dist/source/src-input/duk_heap.h | 723 + - dist/source/src-input/duk_heap_alloc.c | 1217 + - dist/source/src-input/duk_heap_finalize.c | 445 + - dist/source/src-input/duk_heap_hashstring.c | 116 + - dist/source/src-input/duk_heap_markandsweep.c | 1486 + - dist/source/src-input/duk_heap_memory.c | 438 + - dist/source/src-input/duk_heap_misc.c | 187 + - dist/source/src-input/duk_heap_refcount.c | 833 + - dist/source/src-input/duk_heap_stringcache.c | 309 + - dist/source/src-input/duk_heap_stringtable.c | 1043 + - dist/source/src-input/duk_heaphdr.h | 297 + - dist/source/src-input/duk_heaphdr_assert.c | 78 + - dist/source/src-input/duk_henv.h | 45 + - dist/source/src-input/duk_hnatfunc.h | 39 + - dist/source/src-input/duk_hobject.h | 981 + - dist/source/src-input/duk_hobject_alloc.c | 271 + - dist/source/src-input/duk_hobject_assert.c | 127 + - dist/source/src-input/duk_hobject_class.c | 129 + - dist/source/src-input/duk_hobject_enum.c | 713 + - dist/source/src-input/duk_hobject_misc.c | 53 + - dist/source/src-input/duk_hobject_pc2line.c | 244 + - dist/source/src-input/duk_hobject_props.c | 6207 + - dist/source/src-input/duk_hproxy.h | 26 + - dist/source/src-input/duk_hstring.h | 253 + - dist/source/src-input/duk_hstring_assert.c | 13 + - dist/source/src-input/duk_hstring_misc.c | 196 + - dist/source/src-input/duk_hthread.h | 408 + - dist/source/src-input/duk_hthread_alloc.c | 59 + - dist/source/src-input/duk_hthread_builtins.c | 871 + - dist/source/src-input/duk_hthread_misc.c | 97 + - dist/source/src-input/duk_hthread_stacks.c | 407 + - dist/source/src-input/duk_internal.h | 77 + - dist/source/src-input/duk_jmpbuf.h | 24 + - dist/source/src-input/duk_js.h | 116 + - dist/source/src-input/duk_js_arith.c | 137 + - dist/source/src-input/duk_js_bytecode.h | 482 + - dist/source/src-input/duk_js_call.c | 2933 + - dist/source/src-input/duk_js_compiler.c | 8025 ++ - dist/source/src-input/duk_js_compiler.h | 227 + - dist/source/src-input/duk_js_executor.c | 5202 + - dist/source/src-input/duk_js_ops.c | 1478 + - dist/source/src-input/duk_js_var.c | 1797 + - dist/source/src-input/duk_json.h | 68 + - dist/source/src-input/duk_lexer.c | 2440 + - dist/source/src-input/duk_lexer.h | 438 + - dist/source/src-input/duk_numconv.c | 2280 + - dist/source/src-input/duk_numconv.h | 104 + - dist/source/src-input/duk_refcount.h | 725 + - dist/source/src-input/duk_regexp.h | 84 + - dist/source/src-input/duk_regexp_compiler.c | 1287 + - dist/source/src-input/duk_regexp_executor.c | 1029 + - dist/source/src-input/duk_replacements.c | 82 + - dist/source/src-input/duk_replacements.h | 29 + - dist/source/src-input/duk_selftest.c | 678 + - dist/source/src-input/duk_selftest.h | 15 + - dist/source/src-input/duk_strings.h | 169 + - dist/source/src-input/duk_tval.c | 152 + - dist/source/src-input/duk_tval.h | 641 + - dist/source/src-input/duk_unicode.h | 250 + - dist/source/src-input/duk_unicode_support.c | 1259 + - dist/source/src-input/duk_unicode_tables.c | 64 + - dist/source/src-input/duk_util.h | 731 + - dist/source/src-input/duk_util_bitdecoder.c | 157 + - dist/source/src-input/duk_util_bitencoder.c | 43 + - dist/source/src-input/duk_util_bufwriter.c | 286 + - dist/source/src-input/duk_util_cast.c | 160 + - dist/source/src-input/duk_util_double.c | 343 + - dist/source/src-input/duk_util_hashbytes.c | 57 + - dist/source/src-input/duk_util_memory.c | 36 + - dist/source/src-input/duk_util_memrw.c | 148 + - dist/source/src-input/duk_util_misc.c | 183 + - dist/source/src-input/duk_util_tinyrandom.c | 125 + - dist/source/src-input/duktape.h.in | 1320 + - dist/source/src-input/strings.yaml | 1253 + - dist/source/src/duk_config.h | 3805 + - dist/source/src/duk_source_meta.json | 1911 + - dist/source/src/duktape.c | 99784 +++++++++++++++ - dist/source/src/duktape.h | 1462 + - dist/source/tools/combine_src.py | 271 + - dist/source/tools/configure.py | 1005 + - dist/source/tools/create_spdx_license.py | 246 + - dist/source/tools/duk_meta_to_strarray.py | 49 + - dist/source/tools/dukutil.py | 300 + - dist/source/tools/dump_bytecode.py | 276 + - dist/source/tools/extract_caseconv.py | 733 + - dist/source/tools/extract_chars.py | 385 + - dist/source/tools/extract_unique_options.py | 41 + - dist/source/tools/genbuiltins.py | 3221 + - dist/source/tools/genconfig.py | 1542 + - dist/source/tools/json2yaml.py | 5 + - dist/source/tools/merge_debug_meta.py | 48 + - dist/source/tools/prepare_unicode_data.py | 51 + - dist/source/tools/resolve_combined_lineno.py | 26 + - dist/source/tools/scan_strings.py | 135 + - dist/source/tools/scan_used_stridx_bidx.py | 58 + - dist/source/tools/yaml2json.py | 4 + - prep/nondebug/duk_config.h | 3229 + - prep/nondebug/duk_source_meta.json | 1925 + - prep/nondebug/duktape.c | 99924 ++++++++++++++++ - prep/nondebug/duktape.h | 1462 + - 859 files changed, 389919 insertions(+) - create mode 100644 dist/source/AUTHORS.rst - create mode 100644 dist/source/LICENSE.txt - create mode 100644 dist/source/Makefile.cmdline - create mode 100644 dist/source/Makefile.codepage - create mode 100644 dist/source/Makefile.coffee - create mode 100644 dist/source/Makefile.dukdebug - create mode 100644 dist/source/Makefile.eval - create mode 100644 dist/source/Makefile.eventloop - create mode 100644 dist/source/Makefile.hello - create mode 100644 dist/source/Makefile.jsoncbor - create mode 100644 dist/source/Makefile.jxpretty - create mode 100644 dist/source/Makefile.sandbox - create mode 100644 dist/source/Makefile.sharedlibrary - create mode 100644 dist/source/README.rst - create mode 100644 dist/source/config/README.rst - create mode 100644 dist/source/config/architectures.yaml - create mode 100644 dist/source/config/architectures/architecture_arm32.h.in - create mode 100644 dist/source/config/architectures/architecture_arm64.h.in - create mode 100644 dist/source/config/architectures/architecture_emscripten.h.in - create mode 100644 dist/source/config/architectures/architecture_generic.h.in - create mode 100644 dist/source/config/architectures/architecture_m68k.h.in - create mode 100644 dist/source/config/architectures/architecture_mips32.h.in - create mode 100644 dist/source/config/architectures/architecture_mips64.h.in - create mode 100644 dist/source/config/architectures/architecture_powerpc32.h.in - create mode 100644 dist/source/config/architectures/architecture_powerpc64.h.in - create mode 100644 dist/source/config/architectures/architecture_riscv32.h.in - create mode 100644 dist/source/config/architectures/architecture_riscv64.h.in - create mode 100644 dist/source/config/architectures/architecture_sparc32.h.in - create mode 100644 dist/source/config/architectures/architecture_sparc64.h.in - create mode 100644 dist/source/config/architectures/architecture_superh.h.in - create mode 100644 dist/source/config/architectures/architecture_x32.h.in - create mode 100644 dist/source/config/architectures/architecture_x64.h.in - create mode 100644 dist/source/config/architectures/architecture_x86.h.in - create mode 100644 dist/source/config/compilers.yaml - create mode 100644 dist/source/config/compilers/compiler_bcc.h.in - create mode 100644 dist/source/config/compilers/compiler_clang.h.in - create mode 100644 dist/source/config/compilers/compiler_emscripten.h.in - create mode 100644 dist/source/config/compilers/compiler_gcc.h.in - create mode 100644 dist/source/config/compilers/compiler_generic.h.in - create mode 100644 dist/source/config/compilers/compiler_msvc.h.in - create mode 100644 dist/source/config/compilers/compiler_tinyc.h.in - create mode 100644 dist/source/config/compilers/compiler_vbcc.h.in - create mode 100644 dist/source/config/config-options/DUK_USE_32BIT_PTRS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_64BIT_OPS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ALIGN_4.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ALIGN_8.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ALIGN_BY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ALLOW_UNDEFINED_BEHAVIOR.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ARCH_STRING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ARRAY_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ARRAY_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ARRAY_PROP_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ASSERTIONS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ATAN2_WORKAROUNDS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_CREATE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_THROW.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_AVOID_PLATFORM_FUNCPTRS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BASE64_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BASE64_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BOOLEAN_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BRANCH_HINTS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BROWSER_LIKE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BUFFEROBJECT_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BUFLEN16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BUILTIN_INITJS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BYTECODE_DUMP_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BYTEORDER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_BYTEORDER_FORCED.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CACHE_ACTIVATION.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CACHE_CATCHER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CALLSTACK_LIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CBOR_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CBOR_DEC_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CBOR_ENC_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CBOR_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CLANG_PRAGMAS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_COMMONJS_MODULES.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_COMPILER_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_COMPILER_STRING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_COMPUTED_INFINITY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_COMPUTED_NAN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_CPP_EXCEPTIONS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATAPTR16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATAPTR_DEC16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATAPTR_ENC16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_FMT_STRFTIME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_FORMAT_STRING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_GET_LOCAL_TZOFFSET.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_GET_NOW.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_NOW_GETTIMEOFDAY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_NOW_TIME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS_SUBMS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_PARSE_STRING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_PRS_GETDATE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_PRS_STRPTIME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_R.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_S.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DDDPRINT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DDPRINT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUG.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_DUMPHEAP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_LOGGING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_PRINTALERT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_INSPECT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_PAUSE_UNCAUGHT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_THROW_NOTIFY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUGGER_TRANSPORT_TORTURE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUG_BUFSIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUG_LEVEL.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEBUG_WRITE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DEEP_C_STACK.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DOUBLE_BE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DOUBLE_LE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DOUBLE_LINKED_HEAP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DOUBLE_ME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DPRINT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DPRINT_COLORS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DPRINT_RDTSC.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_DUKTAPE_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ENCODING_BUILTINS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ERRCREATE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ERRTHROW.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES6.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES6_OBJECT_PROTO_PROPERTY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES6_OBJECT_SETPROTOTYPEOF.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES6_PROXY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES6_REGEXP_BRACES.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES6_REGEXP_SYNTAX.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES6_UNICODE_ESCAPE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES7.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES7_EXP_OPERATOR.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES8.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ES9.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ESBC_LIMITS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ESBC_MAX_BYTES.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ESBC_MAX_LINENUMBER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXAMPLE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXEC_FUN_LOCAL.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXEC_INDIRECT_BOUND_CHECK.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXEC_PREFER_SIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXEC_REGCONST_OPTIMIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXEC_TIMEOUT_CHECK.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXPLICIT_NULL_INIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXTSTR_FREE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_EXTSTR_INTERN_CHECK.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FASTINT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FAST_REFCOUNT_DEFAULT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FATAL_HANDLER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FATAL_MAXLEN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FILE_IO.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FLEX_C99.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FLEX_ONESIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FLEX_ZEROSIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FULL_TVAL.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FUNCPTR16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FUNCPTR_DEC16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FUNCPTR_ENC16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FUNCTION_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FUNC_FILENAME_PROPERTY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FUNC_NAME_PROPERTY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_FUZZILLI.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GCC_PRAGMAS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GC_TORTURE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GET_RANDOM_DOUBLE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GLOBAL_BINDING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_GLOBAL_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HEAPPTR16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HEAPPTR_DEC16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HEAPPTR_ENC16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HEX_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HEX_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_1.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_2.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_3.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HSTRING_ARRIDX.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HSTRING_CLEN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HSTRING_EXTDATA.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HSTRING_LAZY_CLEN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_HTML_COMMENTS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_IDCHAR_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_INTEGER_BE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_INTEGER_LE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_INTEGER_ME.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_INTERRUPT_COUNTER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_INTERRUPT_DEBUG_FIXUP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JC.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_DECNUMBER_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_DECSTRING_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_DEC_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_EATWHITE_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_ENC_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_QUOTESTRING_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_STRINGIFY_FASTPATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JSON_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_JX.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_LEXER_SLIDING_WINDOW.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_LIGHTFUNC_BUILTINS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_LITCACHE_SIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MATH_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MATH_FMAX.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MATH_FMIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MATH_ROUND.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NATIVE_CALL_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NATIVE_STACK_CHECK.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_MAP_TRAILER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_FUNC_STMT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_GETTER_KEY_ARGUMENT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_JSON_ESC_U2028_U2029.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NO_DOUBLE_ALIASING_SELFTEST.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_NUMBER_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_OBJECT_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_OBJSIZES16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_OCTAL_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_OS_STRING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PACKED_TVAL.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PACKED_TVAL_POSSIBLE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PACK_CLANG_ATTR.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PACK_DUMMY_MEMBER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PACK_GCC_ATTR.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PACK_MSVC_PRAGMA.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PANIC_ABORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PANIC_EXIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PANIC_HANDLER.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PANIC_SEGFAULT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PARANOID_DATE_COMPUTATION.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PARANOID_ERRORS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PARANOID_MATH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PC2LINE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PERFORMANCE_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_POW_NETBSD_WORKAROUND.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_POW_WORKAROUNDS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PREFER_SIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PROMISE_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_RDTSC.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REFCOUNT16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REFCOUNT32.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REFERENCE_COUNTING.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REFLECT_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REGEXP_CANON_BITMAP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REGEXP_CANON_WORKAROUND.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REGEXP_COMPILER_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REGEXP_EXECUTOR_RECLIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REGEXP_SUPPORT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REPL_FPCLASSIFY.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REPL_ISFINITE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REPL_ISINF.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REPL_ISNAN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_REPL_SIGNBIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ROM_GLOBAL_CLONE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ROM_GLOBAL_INHERIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ROM_OBJECTS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ROM_PTRCOMP_FIRST.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ROM_STRINGS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SECTION_B.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SELF_TESTS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SETJMP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SHUFFLE_TORTURE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SIGSETJMP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SOURCE_NONBMP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRHASH16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRHASH_DENSE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRHASH_SKIP_SHIFT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRICT_DECL.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRICT_UTF8_SOURCE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRING_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRLEN16.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_CHAIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_PROBE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_STRTAB_TORTURE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_SYMBOL_BUILTIN.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_TAILCALL.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_TARGET_INFO.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_TRACEBACKS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_TRACEBACK_DEPTH.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_UNALIGNED_ACCESSES_POSSIBLE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_UNDERSCORE_SETJMP.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_UNION_INITIALIZERS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_USER_DECLARE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_USER_INITJS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VALSTACK_GROW_SHIFT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VALSTACK_LIMIT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VALSTACK_UNSAFE.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VARIADIC_MACROS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VERBOSE_ERRORS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VERBOSE_EXECUTOR_ERRORS.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_VOLUNTARY_GC.yaml - create mode 100644 dist/source/config/config-options/DUK_USE_ZERO_BUFFER_DATA.yaml - create mode 100644 dist/source/config/examples/compliance.yaml - create mode 100644 dist/source/config/examples/debugger_support.yaml - create mode 100644 dist/source/config/examples/disable_bufferobjects.yaml - create mode 100644 dist/source/config/examples/disable_es6.yaml - create mode 100644 dist/source/config/examples/enable_debug_print0.yaml - create mode 100644 dist/source/config/examples/enable_debug_print1.yaml - create mode 100644 dist/source/config/examples/enable_debug_print2.yaml - create mode 100644 dist/source/config/examples/enable_fastint.yaml - create mode 100644 dist/source/config/examples/low_memory.yaml - create mode 100644 dist/source/config/examples/low_memory_strip.yaml - create mode 100644 dist/source/config/examples/performance_sensitive.yaml - create mode 100644 dist/source/config/examples/rom_builtins.yaml - create mode 100644 dist/source/config/examples/security_sensitive.yaml - create mode 100644 dist/source/config/examples/shallow_c_stack.yaml - create mode 100644 dist/source/config/examples/timing_sensitive.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_ASSERTIONS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_BUFFEROBJECT_SUPPORT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_BUFLEN16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DATAPTR16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DATAPTR_DEC16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DATAPTR_ENC16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DDDPRINT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DDPRINT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEBUG.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEBUGGER_DUMPHEAP.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_LOGGING.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_PRINTALERT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEBUGGER_SUPPORT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEBUGGER_TRANSPORT_TORTURE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEBUG_BUFSIZE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DECLARE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DEEP_C_STACK.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DLL_BUILD.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DPRINT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DPRINT_COLORS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_DPRINT_RDTSC.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_EXAMPLE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_EXEC_TIMEOUT_CHECK.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_EXTERNAL_STRINGS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_EXTSTR_FREE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_EXTSTR_INTERN_CHECK.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FASTINT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FORCE_ALIGN.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FORCE_BYTEORDER.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FUNCPTR16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FUNCPTR_DEC16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FUNCPTR_ENC16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_GC_TORTURE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_HAVE_CUSTOM_H.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_HEAPPTR16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_HEAPPTR_DEC16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_HEAPPTR_ENC16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_INTERRUPT_COUNTER.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_JSON_STRINGIFY_FASTPATH.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_LIGHTFUNC_BUILTINS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_AUGMENT_ERRORS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_BROWSER_LIKE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_BUFFEROBJECT_SUPPORT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_BYTECODE_DUMP_SUPPORT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_COMMONJS_MODULES.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_ES6_PROXY.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_FILE_IO.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_FUNC_STMT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_JC.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_JSONC.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_JSONX.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_JX.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_MARK_AND_SWEEP.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_MS_STRINGTABLE_RESIZE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_NONSTD_FUNC_STMT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_OCTAL_SUPPORT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_PACKED_TVAL.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_PC2LINE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_REFERENCE_COUNTING.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_REGEXP_SUPPORT.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_SECTION_B.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_SOURCE_NONBMP.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_STRICT_DECL.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_TRACEBACKS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_VERBOSE_ERRORS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_VOLUNTARY_GC.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_NO_ZERO_BUFFER_DATA.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_OBJSIZES16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_PANIC_HANDLER.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_REFCOUNT16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_SEGFAULT_ON_PANIC.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_SELF_TESTS.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_SETJMP.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_SHUFFLE_TORTURE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_SIGSETJMP.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_STRHASH16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_STRICT_UTF8_SOURCE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_STRLEN16.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN_SIZE.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_TARGET_INFO.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_TRACEBACK_DEPTH.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_UNDERSCORE_SETJMP.yaml - create mode 100644 dist/source/config/feature-options/DUK_OPT_USER_INITJS.yaml - create mode 100644 dist/source/config/header-snippets/64bitops.h.in - create mode 100644 dist/source/config/header-snippets/alignment_fillin.h.in - create mode 100644 dist/source/config/header-snippets/architecture_fillins.h.in - create mode 100644 dist/source/config/header-snippets/byteorder_derived.h.in - create mode 100644 dist/source/config/header-snippets/byteorder_fillin.h.in - create mode 100644 dist/source/config/header-snippets/compiler_fillins.h.in - create mode 100644 dist/source/config/header-snippets/cpp_exception_sanity.h.in - create mode 100644 dist/source/config/header-snippets/date_provider.h.in - create mode 100644 dist/source/config/header-snippets/gcc_clang_visibility.h.in - create mode 100644 dist/source/config/header-snippets/inline_workaround.h.in - create mode 100644 dist/source/config/header-snippets/msvc_visibility.h.in - create mode 100644 dist/source/config/header-snippets/object_layout.h.in - create mode 100644 dist/source/config/header-snippets/packed_tval_fillin.h.in - create mode 100644 dist/source/config/header-snippets/platform_conditionalincludes.h.in - create mode 100644 dist/source/config/header-snippets/platform_cppextras.h.in - create mode 100644 dist/source/config/header-snippets/platform_fillins.h.in - create mode 100644 dist/source/config/header-snippets/platform_sharedincludes.h.in - create mode 100644 dist/source/config/header-snippets/reject_fast_math.h.in - create mode 100644 dist/source/config/header-snippets/types1.h.in - create mode 100644 dist/source/config/header-snippets/types2.h.in - create mode 100644 dist/source/config/header-snippets/types_c99.h.in - create mode 100644 dist/source/config/header-snippets/types_legacy.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_AIX.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_AMIGAOS.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_ANDROID.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_APPLE.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_ARM.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_BCC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_BSD.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_C99.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_CLANG.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_CPP.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_CPP11.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_CYGWIN.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_DURANGO.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_EMSCRIPTEN.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_FLASHPLAYER.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_FREEBSD.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_GCC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_HPUX.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_LINUX.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_M68K.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_MINGW.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_MINT.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_MIPS.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_MSVC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_NETBSD.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_NO_STDINT_H.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_OPENBSD.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_ORBIS.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_POSIX.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_PPC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_QNX.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_RISCV.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_SPARC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_SUN.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_SUPERH.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_TINSPIRE.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_TINYC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_TOS.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_UCLIBC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_ULL_CONSTS.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_UNIX.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_VBCC.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_WINDOWS.h.in - create mode 100644 dist/source/config/helper-snippets/DUK_F_X86.h.in - create mode 100644 dist/source/config/platforms.yaml - create mode 100644 dist/source/config/platforms/platform_aix.h.in - create mode 100644 dist/source/config/platforms/platform_amigaos.h.in - create mode 100644 dist/source/config/platforms/platform_android.h.in - create mode 100644 dist/source/config/platforms/platform_apple.h.in - create mode 100644 dist/source/config/platforms/platform_cygwin.h.in - create mode 100644 dist/source/config/platforms/platform_durango.h.in - create mode 100644 dist/source/config/platforms/platform_emscripten.h.in - create mode 100644 dist/source/config/platforms/platform_flashplayer.h.in - create mode 100644 dist/source/config/platforms/platform_generic.h.in - create mode 100644 dist/source/config/platforms/platform_genericbsd.h.in - create mode 100644 dist/source/config/platforms/platform_genericunix.h.in - create mode 100644 dist/source/config/platforms/platform_hpux.h.in - create mode 100644 dist/source/config/platforms/platform_linux.h.in - create mode 100644 dist/source/config/platforms/platform_openbsd.h.in - create mode 100644 dist/source/config/platforms/platform_orbis.h.in - create mode 100644 dist/source/config/platforms/platform_posix.h.in - create mode 100644 dist/source/config/platforms/platform_qnx.h.in - create mode 100644 dist/source/config/platforms/platform_solaris.h.in - create mode 100644 dist/source/config/platforms/platform_tinspire.h.in - create mode 100644 dist/source/config/platforms/platform_tos.h.in - create mode 100644 dist/source/config/platforms/platform_windows.h.in - create mode 100644 dist/source/config/tags.yaml - create mode 100644 dist/source/debugger/Makefile - create mode 100644 dist/source/debugger/README.rst - create mode 100644 dist/source/debugger/duk_classnames.yaml - create mode 100644 dist/source/debugger/duk_debug.js - create mode 100644 dist/source/debugger/duk_debug_meta.json - create mode 100644 dist/source/debugger/duk_debug_proxy.js - create mode 100644 dist/source/debugger/duk_debugcommands.yaml - create mode 100644 dist/source/debugger/duk_debugerrors.yaml - create mode 100644 dist/source/debugger/duk_opcodes.yaml - create mode 100644 dist/source/debugger/package.json - create mode 100644 dist/source/debugger/static/index.html - create mode 100644 dist/source/debugger/static/style.css - create mode 100644 dist/source/debugger/static/webui.js - create mode 100644 dist/source/duk_dist_meta.json - create mode 100644 dist/source/examples/README.rst - create mode 100644 dist/source/examples/alloc-hybrid/README.rst - create mode 100644 dist/source/examples/alloc-hybrid/duk_alloc_hybrid.c - create mode 100644 dist/source/examples/alloc-hybrid/duk_alloc_hybrid.h - create mode 100644 dist/source/examples/alloc-logging/README.rst - create mode 100644 dist/source/examples/alloc-logging/duk_alloc_logging.c - create mode 100644 dist/source/examples/alloc-logging/duk_alloc_logging.h - create mode 100644 dist/source/examples/alloc-logging/log2gnuplot.py - create mode 100644 dist/source/examples/alloc-torture/README.rst - create mode 100644 dist/source/examples/alloc-torture/duk_alloc_torture.c - create mode 100644 dist/source/examples/alloc-torture/duk_alloc_torture.h - create mode 100644 dist/source/examples/cmdline/README.rst - create mode 100644 dist/source/examples/cmdline/duk_cmdline.c - create mode 100644 dist/source/examples/cmdline/duk_cmdline.h - create mode 100644 dist/source/examples/cmdline/duk_cmdline_lowmem.c - create mode 100644 dist/source/examples/codepage-conv/README.rst - create mode 100644 dist/source/examples/codepage-conv/duk_codepage_conv.c - create mode 100644 dist/source/examples/codepage-conv/duk_codepage_conv.h - create mode 100644 dist/source/examples/codepage-conv/test.c - create mode 100644 dist/source/examples/coffee/README.rst - create mode 100644 dist/source/examples/coffee/globals.coffee - create mode 100644 dist/source/examples/coffee/hello.coffee - create mode 100644 dist/source/examples/coffee/mandel.coffee - create mode 100644 dist/source/examples/cpp-exceptions/README.rst - create mode 100644 dist/source/examples/cpp-exceptions/cpp_exceptions.cpp - create mode 100644 dist/source/examples/debug-trans-dvalue/Makefile - create mode 100644 dist/source/examples/debug-trans-dvalue/README.rst - create mode 100644 dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.c - create mode 100644 dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.h - create mode 100644 dist/source/examples/debug-trans-dvalue/test.c - create mode 100644 dist/source/examples/debug-trans-socket/README.rst - create mode 100644 dist/source/examples/debug-trans-socket/duk_trans_socket.h - create mode 100644 dist/source/examples/debug-trans-socket/duk_trans_socket_unix.c - create mode 100644 dist/source/examples/debug-trans-socket/duk_trans_socket_windows.c - create mode 100644 dist/source/examples/dummy-date-provider/README.rst - create mode 100644 dist/source/examples/dummy-date-provider/dummy_date_provider.c - create mode 100644 dist/source/examples/eval/README.rst - create mode 100644 dist/source/examples/eval/eval.c - create mode 100644 dist/source/examples/eventloop/README.rst - create mode 100644 dist/source/examples/eventloop/basic-test.js - create mode 100644 dist/source/examples/eventloop/c_eventloop.c - create mode 100644 dist/source/examples/eventloop/c_eventloop.h - create mode 100644 dist/source/examples/eventloop/c_eventloop.js - create mode 100644 dist/source/examples/eventloop/client-socket-test.js - create mode 100644 dist/source/examples/eventloop/ecma_eventloop.js - create mode 100644 dist/source/examples/eventloop/fileio.c - create mode 100644 dist/source/examples/eventloop/main.c - create mode 100644 dist/source/examples/eventloop/poll.c - create mode 100644 dist/source/examples/eventloop/server-socket-test.js - create mode 100644 dist/source/examples/eventloop/socket.c - create mode 100644 dist/source/examples/eventloop/timer-test.js - create mode 100644 dist/source/examples/guide/README.rst - create mode 100644 dist/source/examples/guide/fib.js - create mode 100644 dist/source/examples/guide/prime.js - create mode 100644 dist/source/examples/guide/primecheck.c - create mode 100644 dist/source/examples/guide/process.js - create mode 100644 dist/source/examples/guide/processlines.c - create mode 100644 dist/source/examples/guide/uppercase.c - create mode 100644 dist/source/examples/hello/README.rst - create mode 100644 dist/source/examples/hello/hello.c - create mode 100644 dist/source/examples/jxpretty/README.rst - create mode 100644 dist/source/examples/jxpretty/jxpretty.c - create mode 100644 dist/source/examples/sandbox/README.rst - create mode 100644 dist/source/examples/sandbox/sandbox.c - create mode 100644 dist/source/extras/README.rst - create mode 100644 dist/source/extras/alloc-pool/Makefile - create mode 100644 dist/source/extras/alloc-pool/README.rst - create mode 100644 dist/source/extras/alloc-pool/duk_alloc_pool.c - create mode 100644 dist/source/extras/alloc-pool/duk_alloc_pool.h - create mode 100644 dist/source/extras/alloc-pool/ptrcomp.yaml - create mode 100644 dist/source/extras/alloc-pool/ptrcomp_fixup.h - create mode 100644 dist/source/extras/alloc-pool/test.c - create mode 100644 dist/source/extras/cbor/Makefile - create mode 100644 dist/source/extras/cbor/README.rst - create mode 100644 dist/source/extras/cbor/cbordecode.py - create mode 100644 dist/source/extras/cbor/duk_cbor.c - create mode 100644 dist/source/extras/cbor/duk_cbor.h - create mode 100644 dist/source/extras/cbor/jsoncbor.c - create mode 100644 dist/source/extras/cbor/run_testvectors.js - create mode 100644 dist/source/extras/console/Makefile - create mode 100644 dist/source/extras/console/README.rst - create mode 100644 dist/source/extras/console/duk_console.c - create mode 100644 dist/source/extras/console/duk_console.h - create mode 100644 dist/source/extras/console/test.c - create mode 100644 dist/source/extras/duk-v1-compat/Makefile - create mode 100644 dist/source/extras/duk-v1-compat/README.rst - create mode 100644 dist/source/extras/duk-v1-compat/duk_v1_compat.c - create mode 100644 dist/source/extras/duk-v1-compat/duk_v1_compat.h - create mode 100644 dist/source/extras/duk-v1-compat/test.c - create mode 100644 dist/source/extras/duk-v1-compat/test_compile1.js - create mode 100644 dist/source/extras/duk-v1-compat/test_compile2.js - create mode 100644 dist/source/extras/duk-v1-compat/test_eval1.js - create mode 100644 dist/source/extras/duk-v1-compat/test_eval2.js - create mode 100644 dist/source/extras/logging/Makefile - create mode 100644 dist/source/extras/logging/README.rst - create mode 100644 dist/source/extras/logging/duk_logging.c - create mode 100644 dist/source/extras/logging/duk_logging.h - create mode 100644 dist/source/extras/logging/test.c - create mode 100644 dist/source/extras/minimal-printf/Makefile - create mode 100644 dist/source/extras/minimal-printf/README.rst - create mode 100644 dist/source/extras/minimal-printf/duk_minimal_printf.c - create mode 100644 dist/source/extras/minimal-printf/duk_minimal_printf.h - create mode 100644 dist/source/extras/minimal-printf/test.c - create mode 100644 dist/source/extras/module-duktape/Makefile - create mode 100644 dist/source/extras/module-duktape/README.rst - create mode 100644 dist/source/extras/module-duktape/duk_module_duktape.c - create mode 100644 dist/source/extras/module-duktape/duk_module_duktape.h - create mode 100644 dist/source/extras/module-duktape/test.c - create mode 100644 dist/source/extras/module-node/Makefile - create mode 100644 dist/source/extras/module-node/README.rst - create mode 100644 dist/source/extras/module-node/duk_module_node.c - create mode 100644 dist/source/extras/module-node/duk_module_node.h - create mode 100644 dist/source/extras/module-node/test.c - create mode 100644 dist/source/extras/print-alert/Makefile - create mode 100644 dist/source/extras/print-alert/README.rst - create mode 100644 dist/source/extras/print-alert/duk_print_alert.c - create mode 100644 dist/source/extras/print-alert/duk_print_alert.h - create mode 100644 dist/source/extras/print-alert/test.c - create mode 100644 dist/source/licenses/commonjs.txt - create mode 100644 dist/source/licenses/lua.txt - create mode 100644 dist/source/licenses/murmurhash2.txt - create mode 100644 dist/source/licenses/splitmix64.txt - create mode 100644 dist/source/licenses/xoroshiro128plus.txt - create mode 100644 dist/source/mandel.js - create mode 100644 dist/source/polyfills/console-minimal.js - create mode 100644 dist/source/polyfills/duktape-buffer.js - create mode 100644 dist/source/polyfills/duktape-error-setter-nonwritable.js - create mode 100644 dist/source/polyfills/duktape-error-setter-writable.js - create mode 100644 dist/source/polyfills/duktape-isfastint.js - create mode 100644 dist/source/polyfills/global.js - create mode 100644 dist/source/polyfills/object-assign.js - create mode 100644 dist/source/polyfills/object-prototype-definegetter.js - create mode 100644 dist/source/polyfills/object-prototype-definesetter.js - create mode 100644 dist/source/polyfills/performance-now.js - create mode 100644 dist/source/polyfills/promise.js - create mode 100644 dist/source/src-input/SpecialCasing-8bit.txt - create mode 100644 dist/source/src-input/SpecialCasing.txt - create mode 100644 dist/source/src-input/UnicodeData-8bit.txt - create mode 100644 dist/source/src-input/UnicodeData.txt - create mode 100644 dist/source/src-input/builtins.yaml - create mode 100644 dist/source/src-input/duk_alloc_default.c - create mode 100644 dist/source/src-input/duk_api_buffer.c - create mode 100644 dist/source/src-input/duk_api_bytecode.c - create mode 100644 dist/source/src-input/duk_api_call.c - create mode 100644 dist/source/src-input/duk_api_codec.c - create mode 100644 dist/source/src-input/duk_api_compile.c - create mode 100644 dist/source/src-input/duk_api_debug.c - create mode 100644 dist/source/src-input/duk_api_heap.c - create mode 100644 dist/source/src-input/duk_api_inspect.c - create mode 100644 dist/source/src-input/duk_api_internal.h - create mode 100644 dist/source/src-input/duk_api_memory.c - create mode 100644 dist/source/src-input/duk_api_object.c - create mode 100644 dist/source/src-input/duk_api_random.c - create mode 100644 dist/source/src-input/duk_api_stack.c - create mode 100644 dist/source/src-input/duk_api_string.c - create mode 100644 dist/source/src-input/duk_api_time.c - create mode 100644 dist/source/src-input/duk_bi_array.c - create mode 100644 dist/source/src-input/duk_bi_boolean.c - create mode 100644 dist/source/src-input/duk_bi_buffer.c - create mode 100644 dist/source/src-input/duk_bi_cbor.c - create mode 100644 dist/source/src-input/duk_bi_date.c - create mode 100644 dist/source/src-input/duk_bi_date_unix.c - create mode 100644 dist/source/src-input/duk_bi_date_windows.c - create mode 100644 dist/source/src-input/duk_bi_duktape.c - create mode 100644 dist/source/src-input/duk_bi_encoding.c - create mode 100644 dist/source/src-input/duk_bi_error.c - create mode 100644 dist/source/src-input/duk_bi_function.c - create mode 100644 dist/source/src-input/duk_bi_global.c - create mode 100644 dist/source/src-input/duk_bi_json.c - create mode 100644 dist/source/src-input/duk_bi_math.c - create mode 100644 dist/source/src-input/duk_bi_number.c - create mode 100644 dist/source/src-input/duk_bi_object.c - create mode 100644 dist/source/src-input/duk_bi_performance.c - create mode 100644 dist/source/src-input/duk_bi_pointer.c - create mode 100644 dist/source/src-input/duk_bi_promise.c - create mode 100644 dist/source/src-input/duk_bi_protos.h - create mode 100644 dist/source/src-input/duk_bi_proxy.c - create mode 100644 dist/source/src-input/duk_bi_reflect.c - create mode 100644 dist/source/src-input/duk_bi_regexp.c - create mode 100644 dist/source/src-input/duk_bi_string.c - create mode 100644 dist/source/src-input/duk_bi_symbol.c - create mode 100644 dist/source/src-input/duk_bi_thread.c - create mode 100644 dist/source/src-input/duk_bi_thrower.c - create mode 100644 dist/source/src-input/duk_dblunion.h - create mode 100644 dist/source/src-input/duk_debug.h - create mode 100644 dist/source/src-input/duk_debug_fixedbuffer.c - create mode 100644 dist/source/src-input/duk_debug_macros.c - create mode 100644 dist/source/src-input/duk_debug_vsnprintf.c - create mode 100644 dist/source/src-input/duk_debugger.c - create mode 100644 dist/source/src-input/duk_debugger.h - create mode 100644 dist/source/src-input/duk_error.h - create mode 100644 dist/source/src-input/duk_error_augment.c - create mode 100644 dist/source/src-input/duk_error_longjmp.c - create mode 100644 dist/source/src-input/duk_error_macros.c - create mode 100644 dist/source/src-input/duk_error_misc.c - create mode 100644 dist/source/src-input/duk_error_throw.c - create mode 100644 dist/source/src-input/duk_exception.h - create mode 100644 dist/source/src-input/duk_fltunion.h - create mode 100644 dist/source/src-input/duk_forwdecl.h - create mode 100644 dist/source/src-input/duk_harray.h - create mode 100644 dist/source/src-input/duk_hboundfunc.h - create mode 100644 dist/source/src-input/duk_hbuffer.h - create mode 100644 dist/source/src-input/duk_hbuffer_alloc.c - create mode 100644 dist/source/src-input/duk_hbuffer_assert.c - create mode 100644 dist/source/src-input/duk_hbuffer_ops.c - create mode 100644 dist/source/src-input/duk_hbufobj.h - create mode 100644 dist/source/src-input/duk_hbufobj_misc.c - create mode 100644 dist/source/src-input/duk_hcompfunc.h - create mode 100644 dist/source/src-input/duk_heap.h - create mode 100644 dist/source/src-input/duk_heap_alloc.c - create mode 100644 dist/source/src-input/duk_heap_finalize.c - create mode 100644 dist/source/src-input/duk_heap_hashstring.c - create mode 100644 dist/source/src-input/duk_heap_markandsweep.c - create mode 100644 dist/source/src-input/duk_heap_memory.c - create mode 100644 dist/source/src-input/duk_heap_misc.c - create mode 100644 dist/source/src-input/duk_heap_refcount.c - create mode 100644 dist/source/src-input/duk_heap_stringcache.c - create mode 100644 dist/source/src-input/duk_heap_stringtable.c - create mode 100644 dist/source/src-input/duk_heaphdr.h - create mode 100644 dist/source/src-input/duk_heaphdr_assert.c - create mode 100644 dist/source/src-input/duk_henv.h - create mode 100644 dist/source/src-input/duk_hnatfunc.h - create mode 100644 dist/source/src-input/duk_hobject.h - create mode 100644 dist/source/src-input/duk_hobject_alloc.c - create mode 100644 dist/source/src-input/duk_hobject_assert.c - create mode 100644 dist/source/src-input/duk_hobject_class.c - create mode 100644 dist/source/src-input/duk_hobject_enum.c - create mode 100644 dist/source/src-input/duk_hobject_misc.c - create mode 100644 dist/source/src-input/duk_hobject_pc2line.c - create mode 100644 dist/source/src-input/duk_hobject_props.c - create mode 100644 dist/source/src-input/duk_hproxy.h - create mode 100644 dist/source/src-input/duk_hstring.h - create mode 100644 dist/source/src-input/duk_hstring_assert.c - create mode 100644 dist/source/src-input/duk_hstring_misc.c - create mode 100644 dist/source/src-input/duk_hthread.h - create mode 100644 dist/source/src-input/duk_hthread_alloc.c - create mode 100644 dist/source/src-input/duk_hthread_builtins.c - create mode 100644 dist/source/src-input/duk_hthread_misc.c - create mode 100644 dist/source/src-input/duk_hthread_stacks.c - create mode 100644 dist/source/src-input/duk_internal.h - create mode 100644 dist/source/src-input/duk_jmpbuf.h - create mode 100644 dist/source/src-input/duk_js.h - create mode 100644 dist/source/src-input/duk_js_arith.c - create mode 100644 dist/source/src-input/duk_js_bytecode.h - create mode 100644 dist/source/src-input/duk_js_call.c - create mode 100644 dist/source/src-input/duk_js_compiler.c - create mode 100644 dist/source/src-input/duk_js_compiler.h - create mode 100644 dist/source/src-input/duk_js_executor.c - create mode 100644 dist/source/src-input/duk_js_ops.c - create mode 100644 dist/source/src-input/duk_js_var.c - create mode 100644 dist/source/src-input/duk_json.h - create mode 100644 dist/source/src-input/duk_lexer.c - create mode 100644 dist/source/src-input/duk_lexer.h - create mode 100644 dist/source/src-input/duk_numconv.c - create mode 100644 dist/source/src-input/duk_numconv.h - create mode 100644 dist/source/src-input/duk_refcount.h - create mode 100644 dist/source/src-input/duk_regexp.h - create mode 100644 dist/source/src-input/duk_regexp_compiler.c - create mode 100644 dist/source/src-input/duk_regexp_executor.c - create mode 100644 dist/source/src-input/duk_replacements.c - create mode 100644 dist/source/src-input/duk_replacements.h - create mode 100644 dist/source/src-input/duk_selftest.c - create mode 100644 dist/source/src-input/duk_selftest.h - create mode 100644 dist/source/src-input/duk_strings.h - create mode 100644 dist/source/src-input/duk_tval.c - create mode 100644 dist/source/src-input/duk_tval.h - create mode 100644 dist/source/src-input/duk_unicode.h - create mode 100644 dist/source/src-input/duk_unicode_support.c - create mode 100644 dist/source/src-input/duk_unicode_tables.c - create mode 100644 dist/source/src-input/duk_util.h - create mode 100644 dist/source/src-input/duk_util_bitdecoder.c - create mode 100644 dist/source/src-input/duk_util_bitencoder.c - create mode 100644 dist/source/src-input/duk_util_bufwriter.c - create mode 100644 dist/source/src-input/duk_util_cast.c - create mode 100644 dist/source/src-input/duk_util_double.c - create mode 100644 dist/source/src-input/duk_util_hashbytes.c - create mode 100644 dist/source/src-input/duk_util_memory.c - create mode 100644 dist/source/src-input/duk_util_memrw.c - create mode 100644 dist/source/src-input/duk_util_misc.c - create mode 100644 dist/source/src-input/duk_util_tinyrandom.c - create mode 100644 dist/source/src-input/duktape.h.in - create mode 100644 dist/source/src-input/strings.yaml - create mode 100644 dist/source/src/duk_config.h - create mode 100644 dist/source/src/duk_source_meta.json - create mode 100644 dist/source/src/duktape.c - create mode 100644 dist/source/src/duktape.h - create mode 100644 dist/source/tools/combine_src.py - create mode 100644 dist/source/tools/configure.py - create mode 100644 dist/source/tools/create_spdx_license.py - create mode 100644 dist/source/tools/duk_meta_to_strarray.py - create mode 100644 dist/source/tools/dukutil.py - create mode 100644 dist/source/tools/dump_bytecode.py - create mode 100644 dist/source/tools/extract_caseconv.py - create mode 100644 dist/source/tools/extract_chars.py - create mode 100644 dist/source/tools/extract_unique_options.py - create mode 100644 dist/source/tools/genbuiltins.py - create mode 100644 dist/source/tools/genconfig.py - create mode 100644 dist/source/tools/json2yaml.py - create mode 100644 dist/source/tools/merge_debug_meta.py - create mode 100644 dist/source/tools/prepare_unicode_data.py - create mode 100644 dist/source/tools/resolve_combined_lineno.py - create mode 100644 dist/source/tools/scan_strings.py - create mode 100644 dist/source/tools/scan_used_stridx_bidx.py - create mode 100644 dist/source/tools/yaml2json.py - create mode 100644 prep/nondebug/duk_config.h - create mode 100644 prep/nondebug/duk_source_meta.json - create mode 100644 prep/nondebug/duktape.c - create mode 100644 prep/nondebug/duktape.h - -diff --git a/dist/source/AUTHORS.rst b/dist/source/AUTHORS.rst -new file mode 100644 -index 0000000..4bfebfc ---- /dev/null -+++ b/dist/source/AUTHORS.rst -@@ -0,0 +1,115 @@ -+=============== -+Duktape authors -+=============== -+ -+Copyright -+========= -+ -+Duktape copyrights are held by its authors. Each author has a copyright -+to their contribution, and agrees to irrevocably license the contribution -+under the Duktape ``LICENSE.txt``. -+ -+Authors -+======= -+ -+Please include an e-mail address, a link to your GitHub profile, or something -+similar to allow your contribution to be identified accurately. -+ -+The following people have contributed code, website contents, or Wiki contents, -+and agreed to irrevocably license their contributions under the Duktape -+``LICENSE.txt`` (in order of appearance): -+ -+* Sami Vaarala -+* Niki Dobrev -+* Andreas Öman -+* László Langó -+* Legimet -+* Karl Skomski -+* Bruce Pascoe -+* René Hollander -+* Julien Hamaide (https://github.com/crazyjul) -+* Sebastian Götte (https://github.com/jaseg) -+* Tomasz Magulski (https://github.com/magul) -+* \D. Bohdan (https://github.com/dbohdan) -+* Ondřej Jirman (https://github.com/megous) -+* Saúl Ibarra Corretgé -+* Jeremy HU -+* Ole André Vadla Ravnås (https://github.com/oleavr) -+* Harold Brenes (https://github.com/harold-b) -+* Oliver Crow (https://github.com/ocrow) -+* Jakub Chłapiński (https://github.com/jchlapinski) -+* Brett Vickers (https://github.com/beevik) -+* Dominik Okwieka (https://github.com/okitec) -+* Remko Tronçon (https://el-tramo.be) -+* Romero Malaquias (rbsm@ic.ufal.br) -+* Michael Drake -+* Steven Don (https://github.com/shdon) -+* Simon Stone (https://github.com/sstone1) -+* \J. McC. (https://github.com/jmhmccr) -+* Jakub Nowakowski (https://github.com/jimvonmoon) -+* Tommy Nguyen (https://github.com/tn0502) -+* Fabrice Fontaine (https://github.com/ffontaine) -+* Christopher Hiller (https://github.com/boneskull) -+* Gonzalo Diethelm (https://github.com/gonzus) -+* Michal Kasperek (https://github.com/michalkas) -+* Andrew Janke (https://github.com/apjanke) -+* Steve Fan (https://github.com/stevefan1999) -+* Edward Betts (https://github.com/edwardbetts) -+* Ozhan Duz (https://github.com/webfolderio) -+* Akos Kiss (https://github.com/akosthekiss) -+* TheBrokenRail (https://github.com/TheBrokenRail) -+* Jesse Doyle (https://github.com/jessedoyle) -+* Gero Kuehn (https://github.com/dc6jgk) -+* James Swift (https://github.com/phraemer) -+* Luis de Bethencourt (https://github.com/luisbg) -+* Ian Whyman (https://github.com/v00d00) -+* Rick Sayre (https://github.com/whorfin) -+* Craig Leres (https://github.com/leres) -+* Maurici Abad (https://github.com/mauriciabad) -+* Nancy Li (https://github.com/NancyLi1013) -+* William Parks (https://github.com/WilliamParks) -+ -+Other contributions -+=================== -+ -+The following people have contributed something other than code (e.g. reported -+bugs, provided ideas, etc; roughly in order of appearance): -+ -+* Greg Burns -+* Anthony Rabine -+* Carlos Costa -+* Aurélien Bouilland -+* Preet Desai (Pris Matic) -+* judofyr (http://www.reddit.com/user/judofyr) -+* Jason Woofenden -+* Michał Przybyś -+* Anthony Howe -+* Conrad Pankoff -+* Jim Schimpf -+* Rajaran Gaunker (https://github.com/zimbabao) -+* Andreas Öman -+* Doug Sanden -+* Josh Engebretson (https://github.com/JoshEngebretson) -+* Remo Eichenberger (https://github.com/remoe) -+* Mamod Mehyar (https://github.com/mamod) -+* David Demelier (https://github.com/markand) -+* Tim Caswell (https://github.com/creationix) -+* Mitchell Blank Jr (https://github.com/mitchblank) -+* https://github.com/yushli -+* Seo Sanghyeon (https://github.com/sanxiyn) -+* Han ChoongWoo (https://github.com/tunz) -+* Joshua Peek (https://github.com/josh) -+* Bruce E. Pascoe (https://github.com/fatcerberus) -+* https://github.com/Kelledin -+* https://github.com/sstruchtrup -+* Michael Drake (https://github.com/tlsa) -+* https://github.com/chris-y -+* Laurent Zubiaur (https://github.com/lzubiaur) -+* Neil Kolban (https://github.com/nkolban) -+* Wilhelm Wanecek (https://github.com/wanecek) -+* Andrew Janke (https://github.com/apjanke) -+* Unamer (https://github.com/unamer) -+* Karl Dahlke (eklhad@gmail.com) -+ -+If you are accidentally missing from this list, send me an e-mail -+(``sami.vaarala@iki.fi``) and I'll fix the omission. -diff --git a/dist/source/LICENSE.txt b/dist/source/LICENSE.txt -new file mode 100644 -index 0000000..783fd1b ---- /dev/null -+++ b/dist/source/LICENSE.txt -@@ -0,0 +1,25 @@ -+=============== -+Duktape license -+=============== -+ -+(http://opensource.org/licenses/MIT) -+ -+Copyright (c) 2013-2020 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 -+in the Software without restriction, including without limitation the rights -+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+copies of the Software, and to permit persons to whom the Software is -+furnished to do so, subject to the following conditions: -+ -+The above copyright notice and this permission notice shall be included in -+all copies or substantial portions of the Software. -+ -+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+THE SOFTWARE. -diff --git a/dist/source/Makefile.cmdline b/dist/source/Makefile.cmdline -new file mode 100644 -index 0000000..235566b ---- /dev/null -+++ b/dist/source/Makefile.cmdline -@@ -0,0 +1,47 @@ -+# -+# Example Makefile for building a program with embedded Duktape. -+# The example program here is the Duktape command line tool. -+# -+ -+DUKTAPE_SOURCES = src/duktape.c -+ -+CMDLINE_SOURCES = \ -+ examples/cmdline/duk_cmdline.c -+ -+CC = gcc -+CCOPTS = -Os -pedantic -std=c99 -Wall -fstrict-aliasing -fomit-frame-pointer -+CCOPTS += -I./examples/cmdline -I./src # duktape.h and duk_config.h must be in include path -+CCLIBS = -lm -+ -+# Enable print() and alert() for command line using an optional extra module. -+CCOPTS += -DDUK_CMDLINE_PRINTALERT_SUPPORT -I./extras/print-alert -+CMDLINE_SOURCES += extras/print-alert/duk_print_alert.c -+ -+# Enable console object (console.log() etc) for command line. -+CCOPTS += -DDUK_CMDLINE_CONSOLE_SUPPORT -I./extras/console -+CMDLINE_SOURCES += extras/console/duk_console.c -+ -+# Enable Duktape.Logger for command line. -+CCOPTS += -DDUK_CMDLINE_LOGGING_SUPPORT -I./extras/logging -+CMDLINE_SOURCES += extras/logging/duk_logging.c -+ -+# Enable Duktape 1.x module loading for command line. -+CCOPTS += -DDUK_CMDLINE_MODULE_SUPPORT -I./extras/module-duktape -+CMDLINE_SOURCES += extras/module-duktape/duk_module_duktape.c -+ -+# If you want linenoise, you can enable these. At the moment linenoise -+# will cause some harmless compilation warnings. -+#CCOPTS += -DDUK_CMDLINE_FANCY -I./linenoise -+#CMDLINE_SOURCES += linenoise/linenoise.c -+#duk: linenoise -+ -+# Use the tools/configure.py utility to modify Duktape default configuration: -+# http://duktape.org/guide.html#compiling -+# http://wiki.duktape.org/Configuring.html -+ -+duk: $(DUKTAPE_SOURCES) $(CMDLINE_SOURCES) -+ $(CC) -o $@ $(DEFINES) $(CCOPTS) $(DUKTAPE_SOURCES) $(CMDLINE_SOURCES) $(CCLIBS) -+ -+linenoise/linenoise.c: linenoise -+linenoise: -+ git clone https://github.com/antirez/linenoise.git -diff --git a/dist/source/Makefile.codepage b/dist/source/Makefile.codepage -new file mode 100644 -index 0000000..f6ef158 ---- /dev/null -+++ b/dist/source/Makefile.codepage -@@ -0,0 +1,6 @@ -+CC = gcc -+ -+codepage: -+ $(CC) -o $@ -std=c99 -O2 -Wall -Wextra -Isrc/ \ -+ src/duktape.c examples/codepage-conv/duk_codepage_conv.c \ -+ examples/codepage-conv/test.c -lm -diff --git a/dist/source/Makefile.coffee b/dist/source/Makefile.coffee -new file mode 100644 -index 0000000..b99eea2 ---- /dev/null -+++ b/dist/source/Makefile.coffee -@@ -0,0 +1,4 @@ -+dummy: -+ coffee -c examples/coffee/globals.coffee -+ coffee -c examples/coffee/hello.coffee -+ coffee -c examples/coffee/mandel.coffee -diff --git a/dist/source/Makefile.dukdebug b/dist/source/Makefile.dukdebug -new file mode 100644 -index 0000000..9fafcc3 ---- /dev/null -+++ b/dist/source/Makefile.dukdebug -@@ -0,0 +1,41 @@ -+# -+# Duktape command line tool with debugger support. -+# -+ -+DUKTAPE_SOURCES = prep/duktape.c -+ -+# Windows (MinGW): use examples/debug-trans-socket/duk_trans_socket_windows.c -+# and link with -lws2_32. -+CMDLINE_SOURCES = \ -+ examples/cmdline/duk_cmdline.c \ -+ examples/debug-trans-socket/duk_trans_socket_unix.c -+ -+CC = gcc -+CCOPTS = -Os -pedantic -std=c99 -Wall -fstrict-aliasing -fomit-frame-pointer -+CCOPTS += -I./prep -I./examples/cmdline -I./examples/debug-trans-socket -+CCOPTS += -DDUK_CMDLINE_DEBUGGER_SUPPORT # enable --debugger in ./duk -+CCLIBS = -lm -+ -+# Enable a few optional modules. -+CCOPTS += -DDUK_CMDLINE_PRINTALERT_SUPPORT -I./extras/print-alert -+CMDLINE_SOURCES += extras/print-alert/duk_print_alert.c -+CCOPTS += -DDUK_CMDLINE_CONSOLE_SUPPORT -I./extras/console -+CMDLINE_SOURCES += extras/console/duk_console.c -+CCOPTS += -DDUK_CMDLINE_LOGGING_SUPPORT -I./extras/logging -+CMDLINE_SOURCES += extras/logging/duk_logging.c -+CCOPTS += -DDUK_CMDLINE_MODULE_SUPPORT -I./extras/module-duktape -+CMDLINE_SOURCES += extras/module-duktape/duk_module_duktape.c -+ -+# Use tools/configure.py to prepare Duktape config header and sources with -+# custom configuration. -+duk: $(CMDLINE_SOURCES) -+ @rm -rf prep -+ python2 tools/configure.py \ -+ --source-directory src-input \ -+ --output-directory prep \ -+ --config-metadata config \ -+ -DDUK_USE_DEBUGGER_SUPPORT \ -+ -DDUK_USE_INTERRUPT_COUNTER \ -+ -DDUK_USE_DEBUGGER_DUMPHEAP \ -+ -DDUK_USE_DEBUGGER_INSPECT -+ $(CC) -o $@ $(DEFINES) $(CCOPTS) $(DUKTAPE_SOURCES) $(CMDLINE_SOURCES) $(CCLIBS) -diff --git a/dist/source/Makefile.eval b/dist/source/Makefile.eval -new file mode 100644 -index 0000000..530f74a ---- /dev/null -+++ b/dist/source/Makefile.eval -@@ -0,0 +1,9 @@ -+# -+# Example Makefile for building the eval example -+# -+ -+CC = gcc -+ -+eval: -+ $(CC) -o $@ -std=c99 -O2 -Wall -Wextra -Isrc/ \ -+ src/duktape.c examples/eval/eval.c -lm -diff --git a/dist/source/Makefile.eventloop b/dist/source/Makefile.eventloop -new file mode 100644 -index 0000000..1a75587 ---- /dev/null -+++ b/dist/source/Makefile.eventloop -@@ -0,0 +1,23 @@ -+# -+# Example Makefile for building the eventloop example -+# -+ -+CC = gcc -+ -+evloop: -+ @echo "NOTE: The eventloop is an example intended to be used on Linux" -+ @echo " or other common UNIX variants. It is not fully portable." -+ @echo "" -+ -+ $(CC) -o $@ -std=c99 -Wall -Wextra -O2 -Isrc \ -+ examples/eventloop/main.c \ -+ examples/eventloop/c_eventloop.c \ -+ examples/eventloop/poll.c \ -+ examples/eventloop/socket.c \ -+ examples/eventloop/fileio.c \ -+ src/duktape.c \ -+ -lm -+ -+ @echo "" -+ @echo "NOTE: You must 'cd examples/eventloop' before you execute the" -+ @echo " eventloop binary: it relies on finding .js files in CWD" -diff --git a/dist/source/Makefile.hello b/dist/source/Makefile.hello -new file mode 100644 -index 0000000..c12b8e0 ---- /dev/null -+++ b/dist/source/Makefile.hello -@@ -0,0 +1,32 @@ -+# -+# Example Makefile for building a program with embedded Duktape. -+# -+# There are two source sets in the distribution: (1) combined sources where -+# you only need duktape.c, duktape.h, and duk_config.h, and (2) separate -+# sources where you have a bunch of source and header files. Whichever -+# you use, simply include the relevant sources into your C project. This -+# Makefile uses the combined source file. -+# -+ -+DUKTAPE_SOURCES = src/duktape.c -+ -+# Compiler options are quite flexible. GCC versions have a significant impact -+# on the size of -Os code, e.g. gcc-4.6 is much worse than gcc-4.5. -+ -+CC = gcc -+CCOPTS = -Os -pedantic -std=c99 -Wall -fstrict-aliasing -fomit-frame-pointer -+CCOPTS += -I./src # for combined sources -+CCLIBS = -lm -+DEFINES = -+ -+# If you want a 32-bit build on a 64-bit host -+#CCOPTS += -m32 -+ -+# Use the tools/configure.py utility to modify Duktape default configuration: -+# http://duktape.org/guide.html#compiling -+# http://wiki.duktape.org/Configuring.html -+ -+# For debugging, use -O0 -g -ggdb, and don't add -fomit-frame-pointer -+ -+hello: $(DUKTAPE_SOURCES) examples/hello/hello.c -+ $(CC) -o $@ $(DEFINES) $(CCOPTS) $(DUKTAPE_SOURCES) examples/hello/hello.c $(CCLIBS) -diff --git a/dist/source/Makefile.jsoncbor b/dist/source/Makefile.jsoncbor -new file mode 100644 -index 0000000..30387a2 ---- /dev/null -+++ b/dist/source/Makefile.jsoncbor -@@ -0,0 +1,10 @@ -+# -+# Example Makefile for building the jsoncbor example -+# -+ -+CC = gcc -+ -+jsoncbor: -+ $(CC) -o $@ -std=c99 -Wall -Wextra -O2 -Isrc -Iextras/cbor \ -+ src/duktape.c extras/cbor/duk_cbor.c extras/cbor/jsoncbor.c \ -+ -lm -diff --git a/dist/source/Makefile.jxpretty b/dist/source/Makefile.jxpretty -new file mode 100644 -index 0000000..7ab00ce ---- /dev/null -+++ b/dist/source/Makefile.jxpretty -@@ -0,0 +1,10 @@ -+# -+# Example Makefile for building the jxpretty example -+# -+ -+CC = gcc -+ -+jxpretty: -+ $(CC) -o $@ -std=c99 -Wall -Wextra -O2 -Isrc \ -+ src/duktape.c examples/jxpretty/jxpretty.c \ -+ -lm -diff --git a/dist/source/Makefile.sandbox b/dist/source/Makefile.sandbox -new file mode 100644 -index 0000000..26bb5ff ---- /dev/null -+++ b/dist/source/Makefile.sandbox -@@ -0,0 +1,9 @@ -+# -+# Example Makefile for building the sandbox example -+# -+ -+CC = gcc -+ -+sandbox: -+ $(CC) -o $@ -std=c99 -O2 -Wall -Wextra -Isrc/ \ -+ src/duktape.c examples/sandbox/sandbox.c -lm -diff --git a/dist/source/Makefile.sharedlibrary b/dist/source/Makefile.sharedlibrary -new file mode 100644 -index 0000000..e37e088 ---- /dev/null -+++ b/dist/source/Makefile.sharedlibrary -@@ -0,0 +1,88 @@ -+# -+# Example of how to build and install locally as a shared library -+# -+# Usage: -+# -+# $ make -f Makefile.sharedlibrary -+# $ sudo make -f Makefile.sharedlibrary install -+# $ make -f Makefile.sharedlibrary duk # --> example 'duk' linked to shared libduktape -+# -+# $ ls -l duk -+# -rwxrwxr-x 1 duktape duktape 19407 Nov 30 15:48 duk -+# -+# $ ldd ./duk -+# linux-vdso.so.1 => (0x00007ffd5ed3c000) -+# libduktape.so.104 => /usr/local/lib/libduktape.so.104 (0x00007fb2f9753000) -+# libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb2f944d000) -+# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb2f9088000) -+# /lib64/ld-linux-x86-64.so.2 (0x00007fb2f9991000) -+# -+# Based on: http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html -+ -+# Soname version must be bumped whenever a binary compatibility change occurs -+# (and should not be bumped when the library is compatible). A simple Duktape -+# convention is to set soname version to (100*MAJOR + MINOR), e.g. 104 for -+# Duktape 1.4.x, so that it gets automatically bumped for major and minor -+# releases (potentially binary incompatible), but not for patch releases. -+DUK_VERSION = 29999 -+SONAME_VERSION = 299 -+REAL_VERSION = $(SONAME_VERSION).$(DUK_VERSION) -+ -+# Mac has an unusual .so naming convention -+ifeq ($(OS),Windows_NT) -+ DETECTED_OS := Windows -+else -+ DETECTED_OS := $(shell uname -s) -+endif -+ifeq ($(DETECTED_OS),Darwin) -+ LD_SONAME_ARG=-install_name -+ SO_SONAME_SUFFIX=$(SONAME_VERSION).so -+ SO_REALNAME_SUFFIX=$(REAL_VERSION).so -+else -+ LD_SONAME_ARG=-soname -+ SO_SONAME_SUFFIX=so.$(SONAME_VERSION) -+ SO_REALNAME_SUFFIX=so.$(REAL_VERSION) -+endif -+ -+# Change to actual path for actual distribution packaging. -+INSTALL_PREFIX = /usr/local -+ -+# The 'noline' variant may be more appropriate for some distributions; it -+# doesn't have #line directives in the combined source. -+DUKTAPE_SRCDIR = ./src -+#DUKTAPE_SRCDIR = ./src-noline -+ -+CC = gcc -+ -+.PHONY: all -+all: libduktape.$(SO_REALNAME_SUFFIX) libduktaped.$(SO_REALNAME_SUFFIX) -+ -+# If the default duk_config.h is not suitable for the distribution, modify it -+# before compiling the shared library and copy the same, edited duk_config.h -+# to $INSTALL_PREFIX/include on installation. -+ -+libduktape.$(SO_REALNAME_SUFFIX): -+ $(CC) -shared -fPIC -Wall -Wextra -Os -Wl,$(LD_SONAME_ARG),libduktape.$(SO_SONAME_SUFFIX) \ -+ -o $@ $(DUKTAPE_SRCDIR)/duktape.c -+ -+libduktaped.$(SO_REALNAME_SUFFIX): -+ $(CC) -shared -fPIC -g -Wall -Wextra -Os -Wl,$(LD_SONAME_ARG),libduktaped.$(SO_SONAME_SUFFIX) \ -+ -o $@ $(DUKTAPE_SRCDIR)/duktape.c -+ -+# Symlinks depend on platform conventions. -+.PHONY: install -+install: libduktape.$(SO_REALNAME_SUFFIX) libduktaped.$(SO_REALNAME_SUFFIX) -+ mkdir -p $(INSTALL_PREFIX)/lib/ -+ cp $+ $(INSTALL_PREFIX)/lib/ -+ rm -f $(INSTALL_PREFIX)/lib/libduktape.so $(INSTALL_PREFIX)/lib/libduktape.$(SO_SONAME_SUFFIX) -+ ln -s libduktape.$(SO_REALNAME_SUFFIX) $(INSTALL_PREFIX)/lib/libduktape.so -+ ln -s libduktape.$(SO_REALNAME_SUFFIX) $(INSTALL_PREFIX)/lib/libduktape.$(SO_SONAME_SUFFIX) -+ rm -f $(INSTALL_PREFIX)/lib/libduktaped.so $(INSTALL_PREFIX)/lib/libduktaped.$(SO_SONAME_SUFFIX) -+ ln -s libduktaped.$(SO_REALNAME_SUFFIX) $(INSTALL_PREFIX)/lib/libduktaped.so -+ ln -s libduktaped.$(SO_REALNAME_SUFFIX) $(INSTALL_PREFIX)/lib/libduktaped.$(SO_SONAME_SUFFIX) -+ mkdir -p $(INSTALL_PREFIX)/include/ -+ cp $(DUKTAPE_SRCDIR)/duktape.h $(DUKTAPE_SRCDIR)/duk_config.h $(INSTALL_PREFIX)/include/ -+ -+CCOPTS = -I./examples/cmdline -+duk: -+ $(CC) $(CCOPTS) -I$(INSTALL_PREFIX)/include -L$(INSTALL_PREFIX)/lib -Wall -Wextra -Os -o $@ ./examples/cmdline/duk_cmdline.c -lduktape -lm -diff --git a/dist/source/README.rst b/dist/source/README.rst -new file mode 100644 -index 0000000..d3b6130 ---- /dev/null -+++ b/dist/source/README.rst -@@ -0,0 +1,129 @@ -+======= -+Duktape -+======= -+ -+Duktape is a small and portable ECMAScript E5/E5.1 implementation. It is -+intended to be easily embeddable into C programs, with a C API similar in -+spirit to Lua's. -+ -+Duktape supports the full E5/E5.1 feature set (with some semantics updated -+from ES2015+) including errors, Unicode strings, and regular expressions, -+a subset of ECMAScript 2015 (E6) and ECMAScript 2016 (E7) features (e.g. -+computed property names, Proxy objects, exponentiation operator, Reflect), -+ES2015 ArrayBuffer/TypedView, Node.js Buffer, performance.now(), CBOR, and -+WHATWG Encoding API living standard. -+ -+Duktape also provides a number of custom features such as error tracebacks, -+additional data types for better C integration, combined reference counting -+and mark-and sweep garbage collector, object finalizers, co-operative -+threads a.k.a. coroutines, tail calls, a built-in debugger protocol, function -+bytecode dump/load, and so on. Bundled extra modules provide functionality -+such as CommonJS module loading and a logging framework. -+ -+You can browse Duktape programmer's API and other documentation at: -+ -+* http://duktape.org/ -+ -+In particular, you should read the getting started section: -+ -+* http://duktape.org/guide.html#gettingstarted -+ -+More examples and how-to articles are in the Duktape Wiki: -+ -+* http://wiki.duktape.org/ -+ -+To build an example command line tool with interactive evaluation (REPL) and -+the ability to run script files:: -+ -+ $ cd -+ $ make -f Makefile.cmdline -+ [...] -+ -+ $ ./duk -+ ((o) Duktape -+ duk> print('Hello world!'); -+ Hello world! -+ = undefined -+ -+ $ ./duk mandel.js -+ [...] -+ -+To integrate Duktape into your program: -+ -+* Use ``tools/configure.py`` to prepare Duktape source and header files -+ for build:: -+ -+ # Duktape options can be customized via command line options. -+ # In this example, enable "fastint" support and disable ES2015 -+ # Proxy support -+ -+ $ python2 tools/configure.py --output-directory duktape-src \ -+ -DDUK_USE_FASTINT -UDUK_USE_ES6_PROXY -+ -+* The output directory (duktape-src) will then contain ``duktape.c``, -+ ``duktape.h``, and ``duk_config.h`` which you include in your build. -+ -+For more details, see: -+ -+* http://duktape.org/guide.html#compiling -+ -+* http://wiki.duktape.org/Configuring.html -+ -+This distributable contains: -+ -+* ``src/``: main Duktape library in a "single source file" format (duktape.c, -+ duktape.h, and duk_config.h; no ``#line`` directives), using Duktape default -+ configuration. -+ -+* ``src-input/``: raw input source files used by ``configure.py`` for creating -+ custom configurations. -+ -+* ``tools/``: various Python tools, such as ``configure.py`` for preparing -+ a ``duk_config.h`` header and Duktape source files for compilation, see -+ http://wiki.duktape.org/Configuring.html. -+ -+* ``config/``: configuration metadata for ``configure.py``. -+ -+* ``examples/``: further examples for using Duktape. Although Duktape -+ itself is widely portable, some of the examples are Linux only. -+ For instance the ``eventloop`` example illustrates how ``setTimeout()`` -+ and other standard timer functions could be implemented on Unix/Linux. -+ -+* ``extras/``: utilities and modules which don't comfortably fit into the -+ main Duktape library because of footprint or portability concerns. -+ Extras are maintained and bug fixed code, but don't have the same version -+ guarantees as the main Duktape library. -+ -+* ``polyfills/``: a few replacement suggestions for non-standard Javascript -+ functions provided by other implementations. -+ -+* ``debugger/``: a debugger with a web UI, see ``debugger/README.rst`` and -+ https://github.com/svaarala/duktape/blob/master/doc/debugger.rst for -+ details on Duktape debugger support. Also contains a JSON debug proxy -+ (one written in Node.js and another in DukLuv) to make talking to the -+ debug target easier. -+ -+* ``licenses/``: licensing information. -+ -+You can find release notes at: -+ -+* https://github.com/svaarala/duktape/blob/master/RELEASES.rst -+ (summary of all versions) -+ -+* https://github.com/svaarala/duktape/blob/master/doc/release-notes-v2-99.rst -+ (more detailed notes for this version) -+ -+This distributable contains Duktape version 2.99.99, created from git -+commit 65f1e02e580796929e92e91ba4776d4b0131beb5 (65f1e02). -+ -+Duktape is copyrighted by its authors (see ``AUTHORS.rst``) and licensed -+under the MIT license (see ``LICENSE.txt``). Duktape contains independent -+implementations, with no included code, of the following algorithms: Lua -+string hash (MIT license), djb2 hash, Murmurhash2 (MIT license), Adi -+Shamir's three-op hash algorithm, xoroshiro128+ PRNG (public domain), -+SplitMix64 PRNG (public domain), and CommonJS module loading specification -+(MIT license). -+ -+Have fun! -+ -+Sami Vaarala (sami.vaarala@iki.fi) -diff --git a/dist/source/config/README.rst b/dist/source/config/README.rst -new file mode 100644 -index 0000000..7be861f ---- /dev/null -+++ b/dist/source/config/README.rst -@@ -0,0 +1,19 @@ -+================= -+Duktape genconfig -+================= -+ -+``genconfig`` is a helper script for coming up with a ``duk_config.h`` for -+compiling Duktape for your platform. -+ -+To support this: -+ -+* It helps to create a ``duk_config.h`` for your platform/compiler -+ combination. You can give a base configuration and then force certain -+ values manually based on a YAML configuration file. -+ -+* It autogenerates documentation for config options based on option metadata -+ files written in YAML. -+ -+NOTE: ``tools/configure.py`` is now the preferred tool for preparing a config -+header (using genconfig.py) and Duktape source files (using other tools) for -+build. -diff --git a/dist/source/config/architectures.yaml b/dist/source/config/architectures.yaml -new file mode 100644 -index 0000000..94f044a ---- /dev/null -+++ b/dist/source/config/architectures.yaml -@@ -0,0 +1,71 @@ -+# Architecture metadata. -+ -+autodetect: -+ - -+ name: x86 -+ check: DUK_F_X86 -+ include: architecture_x86.h.in -+ - -+ name: x64 -+ check: DUK_F_X64 -+ include: architecture_x64.h.in -+ - -+ name: x32 -+ check: DUK_F_X32 -+ include: architecture_x32.h.in -+ - -+ name: ARM 32-bit -+ check: DUK_F_ARM32 -+ include: architecture_arm32.h.in -+ - -+ name: ARM 64-bit -+ check: DUK_F_ARM64 -+ include: architecture_arm64.h.in -+ - -+ name: MIPS 32-bit -+ check: DUK_F_MIPS32 -+ include: architecture_mips32.h.in -+ - -+ name: MIPS 64-bit -+ check: DUK_F_MIPS64 -+ include: architecture_mips64.h.in -+ - -+ name: PowerPC 32-bit -+ check: DUK_F_PPC32 -+ include: architecture_powerpc32.h.in -+ - -+ name: PowerPC 64-bit -+ check: DUK_F_PPC64 -+ include: architecture_powerpc64.h.in -+ - -+ name: SPARC 32-bit -+ check: DUK_F_SPARC32 -+ include: architecture_sparc32.h.in -+ - -+ name: SPARC 64-bit -+ check: DUK_F_SPARC64 -+ include: architecture_sparc64.h.in -+ - -+ name: RISC-V 32-bit -+ check: DUK_F_RISCV32 -+ include: architecture_riscv32.h.in -+ - -+ name: RISC-V 64-bit -+ check: DUK_F_RISCV64 -+ include: architecture_riscv64.h.in -+ - -+ name: SuperH -+ check: DUK_F_SUPERH -+ include: architecture_superh.h.in -+ - -+ name: Motorola 68k -+ check: DUK_F_M68K -+ include: architecture_m68k.h.in -+ - -+ name: Emscripten -+ check: DUK_F_EMSCRIPTEN -+ include: architecture_emscripten.h.in -+ - -+ name: Generic -+ check: null -+ include: architecture_generic.h.in -diff --git a/dist/source/config/architectures/architecture_arm32.h.in b/dist/source/config/architectures/architecture_arm32.h.in -new file mode 100644 -index 0000000..1eb6462 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_arm32.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "arm32" -+/* Byte order varies, so rely on autodetect. */ -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_arm64.h.in b/dist/source/config/architectures/architecture_arm64.h.in -new file mode 100644 -index 0000000..f732ce4 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_arm64.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "arm64" -+/* Byte order varies, so rely on autodetect. */ -+#undef DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_emscripten.h.in b/dist/source/config/architectures/architecture_emscripten.h.in -new file mode 100644 -index 0000000..ea54e71 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_emscripten.h.in -@@ -0,0 +1,5 @@ -+#define DUK_USE_ARCH_STRING "emscripten" -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 1 -+#endif -+#undef DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_generic.h.in b/dist/source/config/architectures/architecture_generic.h.in -new file mode 100644 -index 0000000..783f58b ---- /dev/null -+++ b/dist/source/config/architectures/architecture_generic.h.in -@@ -0,0 +1,3 @@ -+/* These are necessary wild guesses. */ -+#define DUK_USE_ARCH_STRING "generic" -+/* Rely on autodetection for byte order, alignment, and packed tval. */ -diff --git a/dist/source/config/architectures/architecture_m68k.h.in b/dist/source/config/architectures/architecture_m68k.h.in -new file mode 100644 -index 0000000..26260ea ---- /dev/null -+++ b/dist/source/config/architectures/architecture_m68k.h.in -@@ -0,0 +1,5 @@ -+#define DUK_USE_ARCH_STRING "m68k" -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 3 -+#endif -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_mips32.h.in b/dist/source/config/architectures/architecture_mips32.h.in -new file mode 100644 -index 0000000..772f8a2 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_mips32.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "mips32" -+/* MIPS byte order varies so rely on autodetection. */ -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_mips64.h.in b/dist/source/config/architectures/architecture_mips64.h.in -new file mode 100644 -index 0000000..90ddcb3 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_mips64.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "mips64" -+/* MIPS byte order varies so rely on autodetection. */ -+#undef DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_powerpc32.h.in b/dist/source/config/architectures/architecture_powerpc32.h.in -new file mode 100644 -index 0000000..111bc03 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_powerpc32.h.in -@@ -0,0 +1,5 @@ -+#define DUK_USE_ARCH_STRING "ppc32" -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 3 -+#endif -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_powerpc64.h.in b/dist/source/config/architectures/architecture_powerpc64.h.in -new file mode 100644 -index 0000000..d9cb0aa ---- /dev/null -+++ b/dist/source/config/architectures/architecture_powerpc64.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "ppc64" -+/* No forced byteorder (both little and big endian are possible). */ -+#undef DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_riscv32.h.in b/dist/source/config/architectures/architecture_riscv32.h.in -new file mode 100644 -index 0000000..ba42086 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_riscv32.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "riscv32" -+#define DUK_USE_BYTEORDER 1 -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_riscv64.h.in b/dist/source/config/architectures/architecture_riscv64.h.in -new file mode 100644 -index 0000000..dd7eb1f ---- /dev/null -+++ b/dist/source/config/architectures/architecture_riscv64.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "riscv64" -+#define DUK_USE_BYTEORDER 1 -+#undef DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_sparc32.h.in b/dist/source/config/architectures/architecture_sparc32.h.in -new file mode 100644 -index 0000000..ba43b72 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_sparc32.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "sparc32" -+/* SPARC byte order varies so rely on autodetection. */ -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_sparc64.h.in b/dist/source/config/architectures/architecture_sparc64.h.in -new file mode 100644 -index 0000000..37b0dc0 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_sparc64.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "sparc64" -+/* SPARC byte order varies so rely on autodetection. */ -+#undef DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_superh.h.in b/dist/source/config/architectures/architecture_superh.h.in -new file mode 100644 -index 0000000..0aa4d55 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_superh.h.in -@@ -0,0 +1,3 @@ -+#define DUK_USE_ARCH_STRING "sh" -+/* Byte order varies, rely on autodetection. */ -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_x32.h.in b/dist/source/config/architectures/architecture_x32.h.in -new file mode 100644 -index 0000000..2100c76 ---- /dev/null -+++ b/dist/source/config/architectures/architecture_x32.h.in -@@ -0,0 +1,5 @@ -+#define DUK_USE_ARCH_STRING "x32" -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 1 -+#endif -+#define DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_x64.h.in b/dist/source/config/architectures/architecture_x64.h.in -new file mode 100644 -index 0000000..7925b1e ---- /dev/null -+++ b/dist/source/config/architectures/architecture_x64.h.in -@@ -0,0 +1,5 @@ -+#define DUK_USE_ARCH_STRING "x64" -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 1 -+#endif -+#undef DUK_USE_PACKED_TVAL -diff --git a/dist/source/config/architectures/architecture_x86.h.in b/dist/source/config/architectures/architecture_x86.h.in -new file mode 100644 -index 0000000..ae572bd ---- /dev/null -+++ b/dist/source/config/architectures/architecture_x86.h.in -@@ -0,0 +1,14 @@ -+#define DUK_USE_ARCH_STRING "x86" -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 1 -+#endif -+ -+#define DUK_USE_PACKED_TVAL -+ -+/* FreeBSD, -m32, and clang prior to 5.0 has union aliasing issues which -+ * break duk_tval copying. Disable packed duk_tval automatically. -+ */ -+#if defined(DUK_F_FREEBSD) && defined(DUK_F_X86) && \ -+ defined(__clang__) && defined(__clang_major__) && (__clang_major__ < 5) -+#undef DUK_USE_PACKED_TVAL -+#endif -diff --git a/dist/source/config/compilers.yaml b/dist/source/config/compilers.yaml -new file mode 100644 -index 0000000..4399cc2 ---- /dev/null -+++ b/dist/source/config/compilers.yaml -@@ -0,0 +1,35 @@ -+# Compiler metadata. -+ -+autodetect: -+ - -+ name: Clang -+ check: DUK_F_CLANG -+ include: compiler_clang.h.in -+ - -+ name: GCC -+ check: DUK_F_GCC -+ include: compiler_gcc.h.in -+ - -+ name: MSVC -+ check: DUK_F_MSVC -+ include: compiler_msvc.h.in -+ - -+ name: Emscripten -+ check: DUK_F_EMSCRIPTEN -+ include: compiler_emscripten.h.in -+ - -+ name: TinyC -+ check: DUK_F_TINYC -+ include: compiler_tinyc.h.in -+ - -+ name: VBCC -+ check: DUK_F_VBCC -+ include: compiler_vbcc.h.in -+ - -+ name: Bruce's C compiler -+ check: DUK_F_BCC -+ include: compiler_bcc.h.in -+ - -+ name: Generic -+ check: null -+ include: compiler_generic.h.in -diff --git a/dist/source/config/compilers/compiler_bcc.h.in b/dist/source/config/compilers/compiler_bcc.h.in -new file mode 100644 -index 0000000..a12bf62 ---- /dev/null -+++ b/dist/source/config/compilers/compiler_bcc.h.in -@@ -0,0 +1,24 @@ -+#undef DUK_USE_BRANCH_HINTS -+ -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "bcc++" -+#else -+#define DUK_USE_COMPILER_STRING "bcc" -+#endif -+ -+/* Most portable */ -+#undef DUK_USE_VARIADIC_MACROS -+ -+/* Most portable, wastes space */ -+#undef DUK_USE_UNION_INITIALIZERS -+ -+/* Most portable, wastes space */ -+#define DUK_USE_FLEX_ONESIZE -+ -+/* Most portable, potentially wastes space */ -+#define DUK_USE_PACK_DUMMY_MEMBER -+ -+/* BCC, assume we're on x86. */ -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 1 -+#endif -diff --git a/dist/source/config/compilers/compiler_clang.h.in b/dist/source/config/compilers/compiler_clang.h.in -new file mode 100644 -index 0000000..5d38ae4 ---- /dev/null -+++ b/dist/source/config/compilers/compiler_clang.h.in -@@ -0,0 +1,76 @@ -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+/* C99 / C++11 and above: rely on va_copy() which is required. */ -+#define DUK_VA_COPY(dest,src) va_copy(dest,src) -+#else -+/* Clang: assume we have __va_copy() in non-C99 mode. */ -+#define DUK_VA_COPY(dest,src) __va_copy(dest,src) -+#endif -+ -+#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -+ -+#if defined(__clang__) && defined(__has_builtin) -+#if __has_builtin(__builtin_unreachable) -+#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) -+#endif -+#endif -+ -+#define DUK_USE_BRANCH_HINTS -+#define DUK_LIKELY(x) __builtin_expect((x), 1) -+#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -+#if defined(__clang__) && defined(__has_builtin) -+#if __has_builtin(__builtin_unpredictable) -+#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) -+#endif -+#endif -+ -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+#define DUK_NOINLINE __attribute__((noinline)) -+#define DUK_INLINE inline -+#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -+#endif -+ -+/* DUK_HOT */ -+/* DUK_COLD */ -+ -+#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) -+#snippet "msvc_visibility.h.in" -+#else -+#snippet "gcc_clang_visibility.h.in" -+#endif -+ -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "clang" -+#else -+#define DUK_USE_COMPILER_STRING "clang" -+#endif -+ -+#undef DUK_USE_VARIADIC_MACROS -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+#define DUK_USE_VARIADIC_MACROS -+#endif -+ -+#define DUK_USE_UNION_INITIALIZERS -+ -+#undef DUK_USE_FLEX_C99 -+#undef DUK_USE_FLEX_ZEROSIZE -+#undef DUK_USE_FLEX_ONESIZE -+#if defined(DUK_F_C99) -+#define DUK_USE_FLEX_C99 -+#else -+#define DUK_USE_FLEX_ZEROSIZE -+#endif -+ -+#define DUK_USE_CLANG_PRAGMAS -+#define DUK_USE_PACK_CLANG_ATTR -+ -+#if defined(__clang__) && defined(__has_builtin) -+#if __has_builtin(__builtin_bswap64) -+#define DUK_BSWAP64(x) ((duk_uint64_t) __builtin_bswap64((duk_uint64_t) (x))) -+#endif -+#if __has_builtin(__builtin_bswap32) -+#define DUK_BSWAP32(x) ((duk_uint32_t) __builtin_bswap32((duk_uint32_t) (x))) -+#endif -+#if __has_builtin(__builtin_bswap16) -+#define DUK_BSWAP16(x) ((duk_uint16_t) __builtin_bswap16((duk_uint16_t) (x))) -+#endif -+#endif -diff --git a/dist/source/config/compilers/compiler_emscripten.h.in b/dist/source/config/compilers/compiler_emscripten.h.in -new file mode 100644 -index 0000000..dd18700 ---- /dev/null -+++ b/dist/source/config/compilers/compiler_emscripten.h.in -@@ -0,0 +1,45 @@ -+#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -+ -+#if defined(__clang__) && defined(__has_builtin) -+#if __has_builtin(__builtin_unreachable) -+#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) -+#endif -+#endif -+ -+#define DUK_USE_BRANCH_HINTS -+#define DUK_LIKELY(x) __builtin_expect((x), 1) -+#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -+#if defined(__clang__) && defined(__has_builtin) -+#if __has_builtin(__builtin_unpredictable) -+#define DUK_UNPREDICTABLE(x) __builtin_unpredictable((x)) -+#endif -+#endif -+ -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+#define DUK_NOINLINE __attribute__((noinline)) -+#define DUK_INLINE inline -+#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -+#endif -+ -+#snippet "gcc_clang_visibility.h.in" -+ -+#define DUK_USE_COMPILER_STRING "emscripten" -+ -+#undef DUK_USE_VARIADIC_MACROS -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+#define DUK_USE_VARIADIC_MACROS -+#endif -+ -+#define DUK_USE_UNION_INITIALIZERS -+ -+#undef DUK_USE_FLEX_C99 -+#undef DUK_USE_FLEX_ZEROSIZE -+#undef DUK_USE_FLEX_ONESIZE -+#if defined(DUK_F_C99) -+#define DUK_USE_FLEX_C99 -+#else -+#define DUK_USE_FLEX_ZEROSIZE -+#endif -+ -+#undef DUK_USE_GCC_PRAGMAS -+#define DUK_USE_PACK_CLANG_ATTR -diff --git a/dist/source/config/compilers/compiler_gcc.h.in b/dist/source/config/compilers/compiler_gcc.h.in -new file mode 100644 -index 0000000..7750f46 ---- /dev/null -+++ b/dist/source/config/compilers/compiler_gcc.h.in -@@ -0,0 +1,99 @@ -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+/* C99 / C++11 and above: rely on va_copy() which is required. */ -+#define DUK_VA_COPY(dest,src) va_copy(dest,src) -+#else -+/* GCC: assume we have __va_copy() in non-C99 mode. */ -+#define DUK_VA_COPY(dest,src) __va_copy(dest,src) -+#endif -+ -+#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L) && (DUK_F_GCC_VERSION < 50000L) -+/* Since gcc-2.5. -+ * -+ * Disabled temporarily in GCC 5+ because of an unresolved noreturn-related -+ * issue: https://github.com/svaarala/duktape/issues/2155. -+ */ -+#define DUK_NORETURN(decl) decl __attribute__((noreturn)) -+#endif -+ -+#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -+/* Since gcc-4.5. */ -+#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0) -+#endif -+ -+#define DUK_USE_BRANCH_HINTS -+#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L) -+/* GCC: test not very accurate; enable only in relatively recent builds -+ * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html) -+ */ -+#define DUK_LIKELY(x) __builtin_expect((x), 1) -+#define DUK_UNLIKELY(x) __builtin_expect((x), 0) -+#endif -+/* XXX: equivalent of clang __builtin_unpredictable? */ -+ -+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ -+ defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101) -+#define DUK_NOINLINE __attribute__((noinline)) -+#define DUK_INLINE inline -+#define DUK_ALWAYS_INLINE inline __attribute__((always_inline)) -+#endif -+ -+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \ -+ defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40300) -+#define DUK_HOT __attribute__((hot)) -+#define DUK_COLD __attribute__((cold)) -+#endif -+ -+#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) -+#snippet "msvc_visibility.h.in" -+#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000) -+#snippet "gcc_clang_visibility.h.in" -+#endif -+ -+#if defined(DUK_F_MINGW) -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "mingw++" -+#else -+#define DUK_USE_COMPILER_STRING "mingw" -+#endif -+#else -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "g++" -+#else -+#define DUK_USE_COMPILER_STRING "gcc" -+#endif -+#endif -+ -+#undef DUK_USE_VARIADIC_MACROS -+#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__)) -+#define DUK_USE_VARIADIC_MACROS -+#endif -+ -+#define DUK_USE_UNION_INITIALIZERS -+ -+#undef DUK_USE_FLEX_C99 -+#undef DUK_USE_FLEX_ZEROSIZE -+#undef DUK_USE_FLEX_ONESIZE -+#if defined(DUK_F_C99) -+#define DUK_USE_FLEX_C99 -+#else -+#define DUK_USE_FLEX_ZEROSIZE -+#endif -+ -+/* Since 4.6 one can '#pragma GCC diagnostic push/pop'. */ -+#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600) -+#define DUK_USE_GCC_PRAGMAS -+#else -+#undef DUK_USE_GCC_PRAGMAS -+#endif -+ -+#define DUK_USE_PACK_GCC_ATTR -+ -+/* Availability varies based on platform (between GCC 4.4 and 4.8), and there -+ * are apparently some bugs in GCC 4.x. Check for GCC 5.0 before enabling -+ * these to be safe. -+ */ -+#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 50000L) -+#define DUK_BSWAP64(x) ((duk_uint64_t) __builtin_bswap64((duk_uint64_t) (x))) -+#define DUK_BSWAP32(x) ((duk_uint32_t) __builtin_bswap32((duk_uint32_t) (x))) -+#define DUK_BSWAP16(x) ((duk_uint16_t) __builtin_bswap16((duk_uint16_t) (x))) -+#endif -diff --git a/dist/source/config/compilers/compiler_generic.h.in b/dist/source/config/compilers/compiler_generic.h.in -new file mode 100644 -index 0000000..011199c ---- /dev/null -+++ b/dist/source/config/compilers/compiler_generic.h.in -@@ -0,0 +1,24 @@ -+#undef DUK_USE_BRANCH_HINTS -+ -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "generic-c++" -+#else -+#define DUK_USE_COMPILER_STRING "generic" -+#endif -+ -+#undef DUK_USE_VARIADIC_MACROS -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+#define DUK_USE_VARIADIC_MACROS -+#endif -+ -+/* C++ doesn't have standard designated union initializers ({ .foo = 1 }). */ -+#undef DUK_USE_UNION_INITIALIZERS -+#if defined(DUK_F_C99) -+#define DUK_USE_UNION_INITIALIZERS -+#endif -+ -+/* Most portable, wastes space */ -+#define DUK_USE_FLEX_ONESIZE -+ -+/* Most portable, potentially wastes space */ -+#define DUK_USE_PACK_DUMMY_MEMBER -diff --git a/dist/source/config/compilers/compiler_msvc.h.in b/dist/source/config/compilers/compiler_msvc.h.in -new file mode 100644 -index 0000000..f1666c9 ---- /dev/null -+++ b/dist/source/config/compilers/compiler_msvc.h.in -@@ -0,0 +1,84 @@ -+/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */ -+#define DUK_NORETURN(decl) __declspec(noreturn) decl -+ -+/* XXX: DUK_UNREACHABLE for msvc? */ -+ -+#undef DUK_USE_BRANCH_HINTS -+ -+/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */ -+/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */ -+ -+#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS) -+#snippet "msvc_visibility.h.in" -+#endif -+ -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "msvc++" -+#else -+#define DUK_USE_COMPILER_STRING "msvc" -+#endif -+ -+#undef DUK_USE_VARIADIC_MACROS -+#if defined(DUK_F_C99) -+#define DUK_USE_VARIADIC_MACROS -+#elif defined(_MSC_VER) && (_MSC_VER >= 1400) -+/* VS2005+ should have variadic macros even when they're not C99. */ -+#define DUK_USE_VARIADIC_MACROS -+#endif -+ -+#undef DUK_USE_UNION_INITIALIZERS -+#if defined(_MSC_VER) && (_MSC_VER >= 1800) -+/* VS2013+ supports union initializers but there's a bug involving union-inside-struct: -+ * https://connect.microsoft.com/VisualStudio/feedback/details/805981 -+ * The bug was fixed (at least) in VS2015 so check for VS2015 for now: -+ * https://blogs.msdn.microsoft.com/vcblog/2015/07/01/c-compiler-front-end-fixes-in-vs2015/ -+ * Manually tested using VS2013, CL reports 18.00.31101, so enable for VS2013 too. -+ */ -+#define DUK_USE_UNION_INITIALIZERS -+#endif -+ -+#undef DUK_USE_FLEX_C99 -+#undef DUK_USE_FLEX_ZEROSIZE -+#undef DUK_USE_FLEX_ONESIZE -+#if defined(DUK_F_C99) -+#define DUK_USE_FLEX_C99 -+#else -+#define DUK_USE_FLEX_ZEROSIZE -+#endif -+ -+#undef DUK_USE_GCC_PRAGMAS -+ -+#define DUK_USE_PACK_MSVC_PRAGMA -+ -+/* These have been tested from VS2008 onwards; may work in older VS versions -+ * too but not enabled by default. -+ */ -+#if defined(_MSC_VER) && (_MSC_VER >= 1500) -+#define DUK_NOINLINE __declspec(noinline) -+#define DUK_INLINE __inline -+#define DUK_ALWAYS_INLINE __forceinline -+#endif -+ -+#if defined(_MSC_VER) && (_MSC_VER >= 1900) -+#define DUK_SNPRINTF snprintf -+#define DUK_VSNPRINTF vsnprintf -+#else -+/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does -+ * NOT NUL terminate on truncation, but Duktape code never assumes that. -+ * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 -+ */ -+#define DUK_SNPRINTF _snprintf -+#define DUK_VSNPRINTF _vsnprintf -+#endif -+ -+/* Avoid warning when doing DUK_UNREF(some_function). */ -+#if defined(_MSC_VER) && (_MSC_VER < 1500) -+#pragma warning(disable: 4100 4101 4550 4551) -+#define DUK_UNREF(x) -+#else -+#define DUK_UNREF(x) do { __pragma(warning(suppress:4100 4101 4550 4551)) (x); } while (0) -+#endif -+ -+/* Older versions of MSVC don't support the LL/ULL suffix. */ -+#define DUK_U64_CONSTANT(x) x##ui64 -+#define DUK_I64_CONSTANT(x) x##i64 -diff --git a/dist/source/config/compilers/compiler_tinyc.h.in b/dist/source/config/compilers/compiler_tinyc.h.in -new file mode 100644 -index 0000000..2a33010 ---- /dev/null -+++ b/dist/source/config/compilers/compiler_tinyc.h.in -@@ -0,0 +1,18 @@ -+#undef DUK_USE_BRANCH_HINTS -+ -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "tinyc++" -+#else -+#define DUK_USE_COMPILER_STRING "tinyc" -+#endif -+ -+/* http://bellard.org/tcc/tcc-doc.html#SEC7 */ -+#define DUK_USE_VARIADIC_MACROS -+ -+#define DUK_USE_UNION_INITIALIZERS -+ -+/* Most portable, wastes space */ -+#define DUK_USE_FLEX_ONESIZE -+ -+/* Most portable, potentially wastes space */ -+#define DUK_USE_PACK_DUMMY_MEMBER -diff --git a/dist/source/config/compilers/compiler_vbcc.h.in b/dist/source/config/compilers/compiler_vbcc.h.in -new file mode 100644 -index 0000000..d0eae43 ---- /dev/null -+++ b/dist/source/config/compilers/compiler_vbcc.h.in -@@ -0,0 +1,23 @@ -+#undef DUK_USE_BRANCH_HINTS -+ -+#if defined(DUK_F_CPP) -+#define DUK_USE_COMPILER_STRING "vbcc-c++" -+#else -+#define DUK_USE_COMPILER_STRING "vbcc" -+#endif -+ -+#undef DUK_USE_VARIADIC_MACROS -+#if defined(DUK_F_C99) || defined(DUK_F_CPP11) -+#define DUK_USE_VARIADIC_MACROS -+#endif -+ -+/* VBCC supports C99 so check only for C99 for union initializer support. -+ * Designated union initializers would possibly work even without a C99 check. -+ */ -+#undef DUK_USE_UNION_INITIALIZERS -+#if defined(DUK_F_C99) -+#define DUK_USE_UNION_INITIALIZERS -+#endif -+ -+#define DUK_USE_FLEX_ZEROSIZE -+#define DUK_USE_PACK_DUMMY_MEMBER -diff --git a/dist/source/config/config-options/DUK_USE_32BIT_PTRS.yaml b/dist/source/config/config-options/DUK_USE_32BIT_PTRS.yaml -new file mode 100644 -index 0000000..d2214e0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_32BIT_PTRS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_32BIT_PTRS -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Pointers are 32-bit integer compatible. -diff --git a/dist/source/config/config-options/DUK_USE_64BIT_OPS.yaml b/dist/source/config/config-options/DUK_USE_64BIT_OPS.yaml -new file mode 100644 -index 0000000..31fa1d4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_64BIT_OPS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_64BIT_OPS -+introduced: 1.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Use 64-bit integer operations. On some platforms 64-bit types may be -+ available but 64-bit operations don't work correctly e.g. in integer/float -+ casts. -diff --git a/dist/source/config/config-options/DUK_USE_ALIGN_4.yaml b/dist/source/config/config-options/DUK_USE_ALIGN_4.yaml -new file mode 100644 -index 0000000..1cce360 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ALIGN_4.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_ALIGN_4 -+introduced: 1.0.0 -+removed: 1.3.0 -+related: -+ - DUK_USE_ALIGN_BY -+default: false -+tags: -+ - portability -+description: > -+ Use 4-byte alignment for 64-bit integers and IEEE doubles. -+ Replaced by DUK_USE_ALIGN_BY. -diff --git a/dist/source/config/config-options/DUK_USE_ALIGN_8.yaml b/dist/source/config/config-options/DUK_USE_ALIGN_8.yaml -new file mode 100644 -index 0000000..3b3c955 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ALIGN_8.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_ALIGN_8 -+introduced: 1.0.0 -+removed: 1.3.0 -+related: -+ - DUK_USE_ALIGN_BY -+default: false -+tags: -+ - portability -+description: > -+ Use 8-byte alignment for 64-bit integers and IEEE doubles. -+ Replaced by DUK_USE_ALIGN_BY. -diff --git a/dist/source/config/config-options/DUK_USE_ALIGN_BY.yaml b/dist/source/config/config-options/DUK_USE_ALIGN_BY.yaml -new file mode 100644 -index 0000000..bed2f50 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ALIGN_BY.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_ALIGN_BY -+introduced: 1.3.0 -+default: 8 -+tags: -+ - portability -+description: > -+ Use N-byte alignment for 64-bit integers and IEEE doubles -+ (supported values are 1, 4, and 8). -diff --git a/dist/source/config/config-options/DUK_USE_ALLOW_UNDEFINED_BEHAVIOR.yaml b/dist/source/config/config-options/DUK_USE_ALLOW_UNDEFINED_BEHAVIOR.yaml -new file mode 100644 -index 0000000..892aa84 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ALLOW_UNDEFINED_BEHAVIOR.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_ALLOW_UNDEFINED_BEHAVIOR -+introduced: 2.3.0 -+default: false -+tags: -+ - portability -+description: > -+ Allow technically undefined behavior such as out-of-range double-to-integer -+ casts, floating point division by zero, etc. which are likely to work on the -+ majority of platforms. Default is to avoid such behaviors, at the cost of -+ some footprint and performance. -diff --git a/dist/source/config/config-options/DUK_USE_ARCH_STRING.yaml b/dist/source/config/config-options/DUK_USE_ARCH_STRING.yaml -new file mode 100644 -index 0000000..65b22c5 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ARCH_STRING.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_ARCH_STRING -+introduced: 1.0.0 -+default: -+ string: "unknown" -+tags: -+ - portability -+description: > -+ Human-readable architecture string used in e.g. Duktape.env and debugger -+ protocol (example: x64). -diff --git a/dist/source/config/config-options/DUK_USE_ARRAY_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_ARRAY_BUILTIN.yaml -new file mode 100644 -index 0000000..0ca01f1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ARRAY_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ARRAY_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide an Array built-in. -diff --git a/dist/source/config/config-options/DUK_USE_ARRAY_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_ARRAY_FASTPATH.yaml -new file mode 100644 -index 0000000..d223ab7 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ARRAY_FASTPATH.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_ARRAY_FASTPATH -+introduced: 2.0.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+ - compliance -+description: > -+ Enable fast path for Array.prototype operations like push(), pop(), etc. -+ The fast path handles dense Array instances which are more common than -+ sparse arrays or non-array objects (which Array.prototype operations must -+ also support). The fast path assumes that Array.prototype doesn't contain -+ inherited index properties; such properties are very rarely used in -+ practical code. If compliance is critical, disable the fast path. -diff --git a/dist/source/config/config-options/DUK_USE_ARRAY_PROP_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_ARRAY_PROP_FASTPATH.yaml -new file mode 100644 -index 0000000..3b74c8a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ARRAY_PROP_FASTPATH.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_ARRAY_PROP_FASTPATH -+introduced: 2.0.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+ - compliance -+description: > -+ Enable a shallow fast path check for Array index property reads and writes. -+ The fast path assumes Array.prototype doesn't have numeric index properties -+ which would be inherited and affect read/write behavior. This behavior is -+ non-compliant (but practical because such inherited properties are very -+ rare). Disable this option to ensure strict compliance. -diff --git a/dist/source/config/config-options/DUK_USE_ASSERTIONS.yaml b/dist/source/config/config-options/DUK_USE_ASSERTIONS.yaml -new file mode 100644 -index 0000000..1f0cfe8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ASSERTIONS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_ASSERTIONS -+introduced: 1.0.0 -+default: false -+tags: -+ - development -+ - debug -+description: > -+ Enable internal assert checks. These slow down execution considerably -+ so only use when debugging. -diff --git a/dist/source/config/config-options/DUK_USE_ATAN2_WORKAROUNDS.yaml b/dist/source/config/config-options/DUK_USE_ATAN2_WORKAROUNDS.yaml -new file mode 100644 -index 0000000..8ce15ea ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ATAN2_WORKAROUNDS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_ATAN2_WORKAROUNDS -+introduced: 2.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Enable workarounds to common atan2() semantics issues. At least Cygwin/MinGW -+ has such issues, see test-bug-mingw-math-issues.js. -diff --git a/dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_CREATE.yaml b/dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_CREATE.yaml -new file mode 100644 -index 0000000..7d1f45b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_CREATE.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_AUGMENT_ERROR_CREATE -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Augment an ECMAScript error object at creation with tracedata or -+ fileName/lineNumber, or Duktape.errCreate (if enabled). -diff --git a/dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_THROW.yaml b/dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_THROW.yaml -new file mode 100644 -index 0000000..8d16b39 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_AUGMENT_ERROR_THROW.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_AUGMENT_ERROR_THROW -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Augment an ECMAScript error object at throw time with Duktape.errThrow -+ (if enabled). -diff --git a/dist/source/config/config-options/DUK_USE_AVOID_PLATFORM_FUNCPTRS.yaml b/dist/source/config/config-options/DUK_USE_AVOID_PLATFORM_FUNCPTRS.yaml -new file mode 100644 -index 0000000..cbde8c6 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_AVOID_PLATFORM_FUNCPTRS.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_AVOID_PLATFORM_FUNCPTRS -+introduced: 1.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Don't assume that platform functions (e.g. math functions) are actual -+ functions. This option is needed if platform functions may be defined -+ as macros. This is certainly the case with some platform "polyfills" -+ which provide missing C99/C++11 functions through macros, and may be -+ the case with VS2013 (see GH-17). -+ -+ This is now the default: the cost in footprint is negligible. -diff --git a/dist/source/config/config-options/DUK_USE_BASE64_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_BASE64_FASTPATH.yaml -new file mode 100644 -index 0000000..7c6f48d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BASE64_FASTPATH.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_BASE64_FASTPATH -+introduced: 1.4.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for base64 encode/decode. The fast path uses a lookup -+ table at a small cost in footprint. -diff --git a/dist/source/config/config-options/DUK_USE_BASE64_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_BASE64_SUPPORT.yaml -new file mode 100644 -index 0000000..f895e71 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BASE64_SUPPORT.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_BASE64_SUPPORT -+introduced: 2.3.0 -+default: true -+tags: -+ - codec -+description: > -+ Enable base64 encoding/decoding support. -diff --git a/dist/source/config/config-options/DUK_USE_BOOLEAN_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_BOOLEAN_BUILTIN.yaml -new file mode 100644 -index 0000000..0ac5176 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BOOLEAN_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_BOOLEAN_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide a Boolean built-in. -diff --git a/dist/source/config/config-options/DUK_USE_BRANCH_HINTS.yaml b/dist/source/config/config-options/DUK_USE_BRANCH_HINTS.yaml -new file mode 100644 -index 0000000..41ab42e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BRANCH_HINTS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_BRANCH_HINTS -+introduced: 1.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Use branch hints if the compiler supports them. -+ -+# XXX: Unused now, DUK_LIKELY and DUK_UNLIKELY are used instead. -diff --git a/dist/source/config/config-options/DUK_USE_BROWSER_LIKE.yaml b/dist/source/config/config-options/DUK_USE_BROWSER_LIKE.yaml -new file mode 100644 -index 0000000..79d37ef ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BROWSER_LIKE.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_BROWSER_LIKE -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide browser-like bindings: currently print() and alert(). -diff --git a/dist/source/config/config-options/DUK_USE_BUFFEROBJECT_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_BUFFEROBJECT_SUPPORT.yaml -new file mode 100644 -index 0000000..9d2a7b9 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BUFFEROBJECT_SUPPORT.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_BUFFEROBJECT_SUPPORT -+introduced: 1.3.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Enable support for Khronos/ES6 typed arrays and Node.js Buffer objects. -+ -+ When disabled, Duktape custom plain buffer type is present and functional -+ in the C API. Plain buffers have virtual properties and you can read/write -+ buffer contents in ECMAScript code. Plain buffers will still inherit from -+ ArrayBuffer.prototype, but none of the ECMAScript buffer related bindings -+ will work. This includes all ArrayBuffer, typed array, and Node.js Buffer -+ methods. Native bindings which produce plain buffer results (like -+ Duktape.dec()) will still work. -diff --git a/dist/source/config/config-options/DUK_USE_BUFLEN16.yaml b/dist/source/config/config-options/DUK_USE_BUFLEN16.yaml -new file mode 100644 -index 0000000..1e40f4b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BUFLEN16.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_BUFLEN16 -+introduced: 1.1.0 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit buffer length field (for low memory environments). -diff --git a/dist/source/config/config-options/DUK_USE_BUILTIN_INITJS.yaml b/dist/source/config/config-options/DUK_USE_BUILTIN_INITJS.yaml -new file mode 100644 -index 0000000..c6c840d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BUILTIN_INITJS.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_BUILTIN_INITJS -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Use built-in .js init code when creating a new global context. -+ The .js init code (duk_initjs.js) provides some initialization -+ code that's nicer to implement in ECMAScript, and is also used -+ to provide some backwards compatibility bindings which are easy -+ to remove later. -diff --git a/dist/source/config/config-options/DUK_USE_BYTECODE_DUMP_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_BYTECODE_DUMP_SUPPORT.yaml -new file mode 100644 -index 0000000..0662fa3 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BYTECODE_DUMP_SUPPORT.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_BYTECODE_DUMP_SUPPORT -+introduced: 1.3.0 -+default: true -+tags: -+ - api -+description: > -+ Enable support for API calls to dump/load function bytecode. -diff --git a/dist/source/config/config-options/DUK_USE_BYTEORDER.yaml b/dist/source/config/config-options/DUK_USE_BYTEORDER.yaml -new file mode 100644 -index 0000000..afab111 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BYTEORDER.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_BYTEORDER -+introduced: 1.4.0 -+default: 0 # no reasonable automatic default -+tags: -+ - portability -+description: > -+ Byte order for platform: 1 = little endian, 2 = mixed (arm hybrid) endian, -+ 3 = big endian. -+ -+ ARM mixed endian means integers are little endian but IEEE doubles have -+ mixed endianness: big endian bytes 12345678 are ordered in memory as -+ 43218765. See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcfhgcgd.html. -+ -+ (This define should be produced by duk_config.h; currently Duktape internals -+ use automatically derived defines DUK_USE_{INTEGER,DOUBLE}_{LE,BE_ME} -+ instead of using this define directly.) -diff --git a/dist/source/config/config-options/DUK_USE_BYTEORDER_FORCED.yaml b/dist/source/config/config-options/DUK_USE_BYTEORDER_FORCED.yaml -new file mode 100644 -index 0000000..c31fe66 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_BYTEORDER_FORCED.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_BYTEORDER_FORCED -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Byte order was forced (instead of being autodetected). This has no -+ functional impact but the forced status shows up in Duktape.env. -diff --git a/dist/source/config/config-options/DUK_USE_CACHE_ACTIVATION.yaml b/dist/source/config/config-options/DUK_USE_CACHE_ACTIVATION.yaml -new file mode 100644 -index 0000000..6c22b56 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CACHE_ACTIVATION.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_CACHE_ACTIVATION -+introduced: 2.2.0 -+default: true -+tags: -+ - performance -+description: > -+ Cache duk_activation records. When releasing a duk_activation, place it in -+ a free list for later reuse. Mark-and-sweep frees the free list to keep -+ memory usage in check. -diff --git a/dist/source/config/config-options/DUK_USE_CACHE_CATCHER.yaml b/dist/source/config/config-options/DUK_USE_CACHE_CATCHER.yaml -new file mode 100644 -index 0000000..d16627d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CACHE_CATCHER.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_CACHE_CATCHER -+introduced: 2.2.0 -+default: true -+tags: -+ - performance -+description: > -+ Cache duk_catcher records. When releasing a duk_catcher, place it in -+ a free list for later reuse. Mark-and-sweep frees the free list to keep -+ memory usage in check. -diff --git a/dist/source/config/config-options/DUK_USE_CALLSTACK_LIMIT.yaml b/dist/source/config/config-options/DUK_USE_CALLSTACK_LIMIT.yaml -new file mode 100644 -index 0000000..a2c154c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CALLSTACK_LIMIT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_CALLSTACK_LIMIT -+introduced: 2.2.0 -+default: 10000 -+tags: -+ - misc -+description: > -+ Maximum call stack size. If call stack would grow beyond this value, reject -+ the call in progress. This mainly protects against runaway recursion. Note -+ in particular that this limit is unrelated to the native C stack size which -+ has a separate limit define. -diff --git a/dist/source/config/config-options/DUK_USE_CBOR_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_CBOR_BUILTIN.yaml -new file mode 100644 -index 0000000..e983a34 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CBOR_BUILTIN.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_CBOR_BUILTIN -+introduced: 2.5.0 -+default: true -+tags: -+ - codec -+ - cbor -+ - experimental -+description: > -+ Provide a CBOR built-in with CBOR.encode() and CBOR.decode() functions. -diff --git a/dist/source/config/config-options/DUK_USE_CBOR_DEC_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_CBOR_DEC_RECLIMIT.yaml -new file mode 100644 -index 0000000..96e8f7d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CBOR_DEC_RECLIMIT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_CBOR_DEC_RECLIMIT -+introduced: 2.6.0 -+default: 1000 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ Maximum native stack recursion for CBOR decoding. -diff --git a/dist/source/config/config-options/DUK_USE_CBOR_ENC_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_CBOR_ENC_RECLIMIT.yaml -new file mode 100644 -index 0000000..9d8b052 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CBOR_ENC_RECLIMIT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_CBOR_ENC_RECLIMIT -+introduced: 2.6.0 -+default: 1000 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ Maximum native stack recursion for CBOR encoding. -diff --git a/dist/source/config/config-options/DUK_USE_CBOR_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_CBOR_SUPPORT.yaml -new file mode 100644 -index 0000000..8a9d859 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CBOR_SUPPORT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_CBOR_SUPPORT -+introduced: 2.5.0 -+default: true -+tags: -+ - codec -+ - cbor -+ - experimental -+description: > -+ Include CBOR support. When disabled, CBOR functions in the C API (and the -+ CBOR built-in, if enabled) will throw an error. -diff --git a/dist/source/config/config-options/DUK_USE_CLANG_PRAGMAS.yaml b/dist/source/config/config-options/DUK_USE_CLANG_PRAGMAS.yaml -new file mode 100644 -index 0000000..5a8e143 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CLANG_PRAGMAS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_CLANG_PRAGMAS -+introduced: 2.5.0 -+default: false -+tags: -+ - portability -+description: > -+ Use Clang-specific pragmas, e.g. "#pragma clang diagnostic" to suppress -+ unnecessary warnings. -diff --git a/dist/source/config/config-options/DUK_USE_COMMONJS_MODULES.yaml b/dist/source/config/config-options/DUK_USE_COMMONJS_MODULES.yaml -new file mode 100644 -index 0000000..80d37c8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_COMMONJS_MODULES.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_COMMONJS_MODULES -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Enable support for CommonJS modules. When enabled, the global require() -+ function provides a simple module loader facility which depends on the user -+ providing low level module searching functionality. When disabled, the -+ global require() function is present but throws an error. -diff --git a/dist/source/config/config-options/DUK_USE_COMPILER_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_COMPILER_RECLIMIT.yaml -new file mode 100644 -index 0000000..eed337c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_COMPILER_RECLIMIT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_COMPILER_RECLIMIT -+introduced: 1.3.0 -+default: 2500 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ ECMAScript compiler native call stack recursion limit. -diff --git a/dist/source/config/config-options/DUK_USE_COMPILER_STRING.yaml b/dist/source/config/config-options/DUK_USE_COMPILER_STRING.yaml -new file mode 100644 -index 0000000..2f47b01 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_COMPILER_STRING.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_COMPILER_STRING -+introduced: 1.0.0 -+default: -+ string: "unknown" -+tags: -+ - portability -+description: > -+ Human-readable compiler string used in e.g. Duktape.env and debugger -+ protocol (example: gcc). -diff --git a/dist/source/config/config-options/DUK_USE_COMPUTED_INFINITY.yaml b/dist/source/config/config-options/DUK_USE_COMPUTED_INFINITY.yaml -new file mode 100644 -index 0000000..3d3f605 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_COMPUTED_INFINITY.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_COMPUTED_INFINITY -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ The DUK_DOUBLE_INFINITY is not a constant but refers to a global variable -+ with an IEEE double infinity value computed at run-time. Some compilers -+ don't provide a constant for infinity, and may incorrectly evaluate -+ (1 / 0) when doing constant folding. -+ -+ When enabled, define DUK_DOUBLE_INFINITY as duk_computed_infinity. -+ -+# XXX: Remove computed infinity from Duktape itself and let user -+# provide it instead? -diff --git a/dist/source/config/config-options/DUK_USE_COMPUTED_NAN.yaml b/dist/source/config/config-options/DUK_USE_COMPUTED_NAN.yaml -new file mode 100644 -index 0000000..8379feb ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_COMPUTED_NAN.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_COMPUTED_NAN -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ The DUK_DOUBLE_NAN is not a constant but refers to a global variable with -+ an IEEE NaN value computed at run-time. Some compilers don't provide a -+ constant for NaN, and may incorrectly evaluate (0 / 0) when doing -+ constant folding. -+ -+ When enabled, define DUK_DOUBLE_NAN as duk_computed_nan. -+ -+# XXX: Remove computed NaN from Duktape itself and let user provide -+# it instead? -diff --git a/dist/source/config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml -new file mode 100644 -index 0000000..e608bdf ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_COROUTINE_SUPPORT -+introduced: 2.0.0 -+default: true -+tags: -+ - execution -+description: > -+ Enable support for Duktape coroutines, i.e. yield/resume. -diff --git a/dist/source/config/config-options/DUK_USE_CPP_EXCEPTIONS.yaml b/dist/source/config/config-options/DUK_USE_CPP_EXCEPTIONS.yaml -new file mode 100644 -index 0000000..c735666 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_CPP_EXCEPTIONS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_CPP_EXCEPTIONS -+introduced: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Use C++ exceptions instead of setjmp/longjmp for long control transfers. -+ This allows Duktape/C functions written in C++ to use automatic destructors -+ (RAII or scope-based resource management). -diff --git a/dist/source/config/config-options/DUK_USE_DATAPTR16.yaml b/dist/source/config/config-options/DUK_USE_DATAPTR16.yaml -new file mode 100644 -index 0000000..5c424ce ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATAPTR16.yaml -@@ -0,0 +1,21 @@ -+define: DUK_USE_DATAPTR16 -+introduced: 1.1.0 -+related: -+ - DUK_USE_DATAPTR_ENC16 -+ - DUK_USE_DATAPTR_DEC16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable "compression" of arbitrary data pointers into an unsigned 16-bit -+ value. Use together with DUK_USE_DATAPTR_ENC16 and DUK_USE_DATAPTR_DEC16. -+ -+ Pointers compressed are any void pointers in C code, not just the Duktape -+ heap. Also NULL pointer must encode and decode correctly. -+ -+ Currently it is required that NULL encodes to integer 0, and integer -+ 0 decodes to NULL. No other pointer can be encoded to 0. -+ -+ NOTE: This feature option is currently unimplemented, i.e. Duktape won't -+ compress any data pointers at the moment. -diff --git a/dist/source/config/config-options/DUK_USE_DATAPTR_DEC16.yaml b/dist/source/config/config-options/DUK_USE_DATAPTR_DEC16.yaml -new file mode 100644 -index 0000000..1cdf2ec ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATAPTR_DEC16.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_DATAPTR_DEC16 -+introduced: 1.1.0 -+requires: -+ - DUK_USE_DATAPTR16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_USE_DATAPTR16 for arbitrary data pointer compression. -+ DUK_USE_DATAPTR_DEC16(udata,x) is a macro with a userdata and duk_uint16_t -+ argument, and a void ptr return value. The userdata argument is the heap -+ userdata value given at heap creation. -diff --git a/dist/source/config/config-options/DUK_USE_DATAPTR_ENC16.yaml b/dist/source/config/config-options/DUK_USE_DATAPTR_ENC16.yaml -new file mode 100644 -index 0000000..988e6b7 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATAPTR_ENC16.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_DATAPTR_ENC16 -+introduced: 1.1.0 -+requires: -+ - DUK_USE_DATAPTR16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_USE_DATAPTR16 for arbitrary data pointer compression. -+ DUK_USE_DATAPTR_ENC16(udata,p) is a macro with a userdata and void ptr -+ argument, and a duk_uint16_t return value. The userdata argument is the -+ heap userdata value given at heap creation. Currently it is required that -+ NULL encodes to integer 0, and integer 0 decodes to NULL. No other pointer -+ can be encoded to 0. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_DATE_BUILTIN.yaml -new file mode 100644 -index 0000000..f233b4a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_DATE_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide a Date built-in. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_FMT_STRFTIME.yaml b/dist/source/config/config-options/DUK_USE_DATE_FMT_STRFTIME.yaml -new file mode 100644 -index 0000000..9477a4b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_FMT_STRFTIME.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_DATE_FMT_STRFTIME -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use strftime() to format Date values in native, platform specific format -+ before falling back into ISO 8601. When enabled, appropriate date/time -+ headers must be included. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_FORMAT_STRING.yaml b/dist/source/config/config-options/DUK_USE_DATE_FORMAT_STRING.yaml -new file mode 100644 -index 0000000..6146b5e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_FORMAT_STRING.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_FORMAT_STRING -+introduced: 1.3.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Optional macro for formatting a date in a platform dependent manner, -+ see datetime.rst. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_GET_LOCAL_TZOFFSET.yaml b/dist/source/config/config-options/DUK_USE_DATE_GET_LOCAL_TZOFFSET.yaml -new file mode 100644 -index 0000000..572f3c4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_GET_LOCAL_TZOFFSET.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_GET_LOCAL_TZOFFSET -+introduced: 1.3.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Mandatory macro for getting the local time offset for a given datetime, -+ see datetime.rst. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_GET_NOW.yaml b/dist/source/config/config-options/DUK_USE_DATE_GET_NOW.yaml -new file mode 100644 -index 0000000..b89d9b0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_GET_NOW.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_DATE_GET_NOW -+introduced: 1.3.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Mandatory macro for getting the current time, see datetime.rst. The macro -+ is allowed (and recommended) to return millisecond fractions. The fractions -+ are truncated by the Date built-in, but are available via duk_get_now() C -+ API call. -+ -+ If the time provided experiences time jumps or doesn't advance in realtime -+ (which is useful in some time virtualization scenarios), consider defining -+ DUK_USE_GET_MONOTONIC_TIME. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_NOW_GETTIMEOFDAY.yaml b/dist/source/config/config-options/DUK_USE_DATE_NOW_GETTIMEOFDAY.yaml -new file mode 100644 -index 0000000..a642177 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_NOW_GETTIMEOFDAY.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_NOW_GETTIMEOFDAY -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use gettimeofday() to get current datetime. When enabled, appropriate -+ date/time headers must be included. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_NOW_TIME.yaml b/dist/source/config/config-options/DUK_USE_DATE_NOW_TIME.yaml -new file mode 100644 -index 0000000..675fab8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_NOW_TIME.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_DATE_NOW_TIME -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use time() to get current datetime, with the limitation that datetime is -+ limited to one second resolution. When enabled, appropriate date/time -+ headers must be included. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS.yaml b/dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS.yaml -new file mode 100644 -index 0000000..de24e39 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_DATE_NOW_WINDOWS -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use Win32 API calls to get current datetime. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS_SUBMS.yaml b/dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS_SUBMS.yaml -new file mode 100644 -index 0000000..bb5b77f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_NOW_WINDOWS_SUBMS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_NOW_WINDOWS_SUBMS -+introduced: 2.2.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Like DUK_USE_DATE_NOW_WINDOWS but use GetSystemTimePreciseAsFileTime(), -+ available since Windows 8, for sub-millisecond resolution. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_PARSE_STRING.yaml b/dist/source/config/config-options/DUK_USE_DATE_PARSE_STRING.yaml -new file mode 100644 -index 0000000..7fe0ac2 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_PARSE_STRING.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_PARSE_STRING -+introduced: 1.3.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Optional macro for parsing a date in a platform dependent manner, -+ see datetime.rst. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_PRS_GETDATE.yaml b/dist/source/config/config-options/DUK_USE_DATE_PRS_GETDATE.yaml -new file mode 100644 -index 0000000..c224d16 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_PRS_GETDATE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_DATE_PRS_GETDATE -+introduced: 1.3.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use getdate_r() to parse a platform specific datetime string into ECMAScript -+ time. getdate_r() depends on DATEMSK being set so this is not always very -+ convenient for an embedded interpreter. When enabled, appropriate date/time -+ headers must be included. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_PRS_STRPTIME.yaml b/dist/source/config/config-options/DUK_USE_DATE_PRS_STRPTIME.yaml -new file mode 100644 -index 0000000..2d7eb51 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_PRS_STRPTIME.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_PRS_STRPTIME -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use strptime() to parse a platform specific datetime string into ECMAScript -+ time. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME.yaml b/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME.yaml -new file mode 100644 -index 0000000..53c8fa0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_DATE_TZO_GMTIME -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use gmtime() to get local time offset at a certain time. -+ When enabled, appropriate date/time headers must be included. -+ -+ Since gmtime() is not re-entrant, this is not thread safe. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_R.yaml b/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_R.yaml -new file mode 100644 -index 0000000..5ac25c3 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_R.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_TZO_GMTIME_R -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use gmtime_r() to get local time offset at a certain time. -+ When enabled, appropriate date/time headers must be included. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_S.yaml b/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_S.yaml -new file mode 100644 -index 0000000..13779e7 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_TZO_GMTIME_S.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_DATE_TZO_GMTIME_S -+introduced: 2.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use gmtime_s() to get local time offset at a certain time. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS.yaml b/dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS.yaml -new file mode 100644 -index 0000000..dbfa9a8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_DATE_TZO_WINDOWS -+introduced: 1.0.0 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use Win32 API calls to get local time offset at a certain time. -diff --git a/dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml b/dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml -new file mode 100644 -index 0000000..f0639da ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DATE_TZO_WINDOWS_NO_DST.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DATE_TZO_WINDOWS_NO_DST -+introduced: 2.0.1 -+default: false -+tags: -+ - date -+ - portability -+description: > -+ Use Win32 API calls to get local time offset at a certain time. -+ Does not take into account daylight savings time. -diff --git a/dist/source/config/config-options/DUK_USE_DDDPRINT.yaml b/dist/source/config/config-options/DUK_USE_DDDPRINT.yaml -new file mode 100644 -index 0000000..5dc055d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DDDPRINT.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DDDPRINT -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - debug -+description: > -+ Enable even more debug printouts. Not recommended unless you have -+ grep handy. Replaced by DUK_USE_DEBUG_LEVEL. -diff --git a/dist/source/config/config-options/DUK_USE_DDPRINT.yaml b/dist/source/config/config-options/DUK_USE_DDPRINT.yaml -new file mode 100644 -index 0000000..6406f0f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DDPRINT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_DDPRINT -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - debug -+description: > -+ Enable more debug printouts. Replaced by DUK_USE_DEBUG_LEVEL. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUG.yaml b/dist/source/config/config-options/DUK_USE_DEBUG.yaml -new file mode 100644 -index 0000000..09b9785 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUG.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_DEBUG -+introduced: 1.0.0 -+default: false -+tags: -+ - debug -+description: > -+ Enable debug code in Duktape internals. Without this option other -+ debugging options (such as DUK_USE_DEBUG_LEVEL and DUK_USE_DEBUG_WRITE) -+ have no effect. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_DUMPHEAP.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_DUMPHEAP.yaml -new file mode 100644 -index 0000000..ef9c8d8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_DUMPHEAP.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_DEBUGGER_DUMPHEAP -+introduced: 1.2.0 -+# Option is ignored unless debugger support is enabled. -+#requires: -+# - DUK_USE_DEBUGGER_SUPPORT -+default: false -+tags: -+ - debugger -+description: > -+ Support the DumpHeap command. This is optional because the command is not -+ always needed. The command also has a relatively large footprint (about -+ 10% of debugger code); in absolute terms it's about 1kB of code footprint. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_LOGGING.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_LOGGING.yaml -new file mode 100644 -index 0000000..66fc0d9 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_LOGGING.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_DEBUGGER_FWD_LOGGING -+introduced: 1.2.0 -+removed: 2.0.0 -+# Option is ignored unless debugger support is enabled. -+#requires: -+# - DUK_USE_DEBUGGER_SUPPORT -+default: false -+tags: -+ - debugger -+description: > -+ Forward log writes using the built-in logging framework to the debug client. -+ Forwarding happens from the Duktape.Logger.prototype.info() etc calls before -+ the raw() function is called, so that logging is forwarded even if you -+ replace the backend. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_PRINTALERT.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_PRINTALERT.yaml -new file mode 100644 -index 0000000..842e541 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_FWD_PRINTALERT.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_DEBUGGER_FWD_PRINTALERT -+introduced: 1.2.0 -+removed: 2.0.0 -+# Option is ignored unless debugger support is enabled. -+#requires: -+# - DUK_USE_DEBUGGER_SUPPORT -+default: false -+tags: -+ - debugger -+description: > -+ Forward calls to the built-in print() and alert() function to the debug -+ client. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_INSPECT.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_INSPECT.yaml -new file mode 100644 -index 0000000..299e14d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_INSPECT.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_DEBUGGER_INSPECT -+introduced: 1.5.0 -+# Option is ignored unless debugger support is enabled. -+#requires: -+# - DUK_USE_DEBUGGER_SUPPORT -+default: false -+tags: -+ - debugger -+description: > -+ Support debugger heap object inspection commands GetHeapObjInfo, -+ GetObjPropDesc, GetObjPropDescRange. These are optional because the -+ commands have a relatively high code footprint (about 3kB) and are not -+ always needed. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_PAUSE_UNCAUGHT.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_PAUSE_UNCAUGHT.yaml -new file mode 100644 -index 0000000..250d0d1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_PAUSE_UNCAUGHT.yaml -@@ -0,0 +1,17 @@ -+define: DUK_USE_DEBUGGER_PAUSE_UNCAUGHT -+introduced: 1.4.0 -+# Option is ignored unless debugger support is enabled. -+#requires: -+# - DUK_USE_DEBUGGER_SUPPORT -+related: -+ - DUK_USE_DEBUGGER_THROW_NOTIFY -+default: false -+tags: -+ - debugger -+description: > -+ Pause automatically when an error is about to be thrown and that error is -+ (most likely) not going to be caught. An error is considered uncaught if -+ there is no active catch clause in the current thread or in the current -+ thread's resumer chain. This is not 100% accurate because there may be a -+ finally clause which neutralizes the throw (e.g. converts it to a "return" -+ or a "continue"). -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_SUPPORT.yaml -new file mode 100644 -index 0000000..a67ac73fd ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_SUPPORT.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_DEBUGGER_SUPPORT -+introduced: 1.2.0 -+requires: -+ - DUK_USE_INTERRUPT_COUNTER -+default: false -+tags: -+ - debugger -+description: > -+ Enable support for Duktape debug protocol (see doc/debugger.rst) and the -+ debug API calls (duk_debugger_attach(), duk_debugger_detach(), etc). -+ This adds about 10kB of code footprint at the moment. -+ -+ This option requires DUK_USE_INTERRUPT_COUNTER. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_THROW_NOTIFY.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_THROW_NOTIFY.yaml -new file mode 100644 -index 0000000..b323e60 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_THROW_NOTIFY.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_DEBUGGER_THROW_NOTIFY -+introduced: 1.4.0 -+# Option is ignored unless debugger support is enabled. -+#requires: -+# - DUK_USE_DEBUGGER_SUPPORT -+related: -+ - DUK_USE_DEBUGGER_PAUSE_UNCAUGHT -+default: true -+tags: -+ - debugger -+description: > -+ Send a Throw notify when an error is about to be thrown. The Throw notify -+ also indicates if an error is fatal (most likely not caught) which is very -+ useful in debugging. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUGGER_TRANSPORT_TORTURE.yaml b/dist/source/config/config-options/DUK_USE_DEBUGGER_TRANSPORT_TORTURE.yaml -new file mode 100644 -index 0000000..70a0f35 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUGGER_TRANSPORT_TORTURE.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_DEBUGGER_TRANSPORT_TORTURE -+introduced: 1.2.0 -+# Option is ignored unless debugger support is enabled. -+#requires: -+# - DUK_USE_DEBUGGER_SUPPORT -+default: false -+tags: -+ - debugger -+ - development -+ - torture -+description: > -+ Development time option: force debugger transport torture. Concretely this -+ now causes Duktape to read/write debug protocol data in 1-byte increments, -+ which stresses message parsing and transport code. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUG_BUFSIZE.yaml b/dist/source/config/config-options/DUK_USE_DEBUG_BUFSIZE.yaml -new file mode 100644 -index 0000000..1d93415 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUG_BUFSIZE.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_DEBUG_BUFSIZE -+introduced: 1.0.0 -+related: # not strictly required, value is defined even when DUK_USE_DEBUG not defined -+ - DUK_USE_DEBUG -+default: 65536 -+tags: -+ - debug -+description: > -+ Debug code uses a static buffer as a formatting temporary to avoid side -+ effects in debug prints. The static buffer is large by default, which -+ may be an issue in constrained environments. You can set the buffer size -+ manually with this option, e.g. set DUK_USE_DEBUG_BUFSIZE to 2048. -diff --git a/dist/source/config/config-options/DUK_USE_DEBUG_LEVEL.yaml b/dist/source/config/config-options/DUK_USE_DEBUG_LEVEL.yaml -new file mode 100644 -index 0000000..aa0265e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUG_LEVEL.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_DEBUG_LEVEL -+introduced: 2.0.0 -+default: 0 -+tags: -+ - debug -+description: > -+ Set debug print level when DUK_USE_DEBUG is enabled. The level can be -+ 0 (minimal), 1 (verbose), 2 (very verbose). -diff --git a/dist/source/config/config-options/DUK_USE_DEBUG_WRITE.yaml b/dist/source/config/config-options/DUK_USE_DEBUG_WRITE.yaml -new file mode 100644 -index 0000000..46599be ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEBUG_WRITE.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_DEBUG_WRITE -+introduced: 2.0.0 -+default: false -+tags: -+ - debug -+description: > -+ Macro used for Duktape debug log writes (when DUK_USE_DEBUG is enabled). -+ There's no default provider to avoid a dependency on platform I/O calls. -+ The macro is called like a function with the following prototype: -+ "void DUK_USE_DEBUG_WRITE(long level, const char *file, long line, const char *func, const char *msg)". -+ The "file", "func", and "msg" arguments are non-NULL strings, though NULLs -+ should be handled as good practice (it's ultimately up to duk_config.h -+ whether NULL values are possible). -+ -+ See http://wiki.duktape.org/HowtoDebugPrints.html for more information -+ and examples. -diff --git a/dist/source/config/config-options/DUK_USE_DEEP_C_STACK.yaml b/dist/source/config/config-options/DUK_USE_DEEP_C_STACK.yaml -new file mode 100644 -index 0000000..82de994 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DEEP_C_STACK.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_DEEP_C_STACK -+introduced: 1.0.0 -+removed: 1.3.0 -+default: true -+tags: -+ - portability -+description: > -+ Assume deep C stacks are not an issue on the target platform; on some -+ embedded platforms the native C stack is very limited (e.g. 32-64 kB) -+ and overrunning the stack leads to difficult-to-diagnose problems. -+ -+ Removed in Duktape 1.3.0, replaced by explicit recursion limits. -diff --git a/dist/source/config/config-options/DUK_USE_DOUBLE_BE.yaml b/dist/source/config/config-options/DUK_USE_DOUBLE_BE.yaml -new file mode 100644 -index 0000000..a63d9d9 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DOUBLE_BE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_DOUBLE_BE -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+conflicts: -+ - DUK_USE_DOUBLE_LE -+ - DUK_USE_DOUBLE_ME -+tags: -+ - portability -+description: > -+ IEEE double memory representation is big endian on the target platform. -diff --git a/dist/source/config/config-options/DUK_USE_DOUBLE_LE.yaml b/dist/source/config/config-options/DUK_USE_DOUBLE_LE.yaml -new file mode 100644 -index 0000000..fcbcbc0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DOUBLE_LE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_DOUBLE_LE -+introduced: 1.0.0 -+removed: 1.4.0 -+default: true -+conflicts: -+ - DUK_USE_DOUBLE_BE -+ - DUK_USE_DOUBLE_ME -+tags: -+ - portability -+description: > -+ IEEE double memory representation is little endian on the target platform. -diff --git a/dist/source/config/config-options/DUK_USE_DOUBLE_LINKED_HEAP.yaml b/dist/source/config/config-options/DUK_USE_DOUBLE_LINKED_HEAP.yaml -new file mode 100644 -index 0000000..8e55973 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DOUBLE_LINKED_HEAP.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_DOUBLE_LINKED_HEAP -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Use a double-linked duk_heaphdr structure. Required when reference -+ counting is enabled. -+ -+# XXX: This must currently always match DUK_USE_REFERENCE_COUNTING -+# so remove as a separate option? -diff --git a/dist/source/config/config-options/DUK_USE_DOUBLE_ME.yaml b/dist/source/config/config-options/DUK_USE_DOUBLE_ME.yaml -new file mode 100644 -index 0000000..61a4cda ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DOUBLE_ME.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_DOUBLE_ME -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+conflicts: -+ - DUK_USE_DOUBLE_LE -+ - DUK_USE_DOUBLE_BE -+tags: -+ - portability -+description: > -+ IEEE double memory representation is mixed endian on the target platform. -+ In other words the logical bytes ABCDEFGH are represented in memory as -+ DCBAHGFE. This endianness is used by some ARM platforms. -diff --git a/dist/source/config/config-options/DUK_USE_DPRINT.yaml b/dist/source/config/config-options/DUK_USE_DPRINT.yaml -new file mode 100644 -index 0000000..0895eb6 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DPRINT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_DPRINT -+introduced: 1.0.0 -+removed: 2.0.0 -+requires: -+ - DUK_USE_DEBUG -+default: false -+tags: -+ - debug -+description: > -+ Enable debug printouts. Replaced by DUK_USE_DEBUG_LEVEL. -diff --git a/dist/source/config/config-options/DUK_USE_DPRINT_COLORS.yaml b/dist/source/config/config-options/DUK_USE_DPRINT_COLORS.yaml -new file mode 100644 -index 0000000..e1b65f1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DPRINT_COLORS.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_DPRINT_COLORS -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - debug -+description: > -+ Enable coloring of debug prints with ANSI escape codes -+ (http://en.wikipedia.org/wiki/ANSI_escape_code). The behavior is not -+ sensitive to terminal settings. -diff --git a/dist/source/config/config-options/DUK_USE_DPRINT_RDTSC.yaml b/dist/source/config/config-options/DUK_USE_DPRINT_RDTSC.yaml -new file mode 100644 -index 0000000..e154585 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DPRINT_RDTSC.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_DPRINT_RDTSC -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - debug -+description: > -+ Print RDTSC cycle count in debug prints if available. -diff --git a/dist/source/config/config-options/DUK_USE_DUKTAPE_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_DUKTAPE_BUILTIN.yaml -new file mode 100644 -index 0000000..c36aebf ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_DUKTAPE_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_DUKTAPE_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - duktape -+description: > -+ Provide a Duktape built-in. -diff --git a/dist/source/config/config-options/DUK_USE_ENCODING_BUILTINS.yaml b/dist/source/config/config-options/DUK_USE_ENCODING_BUILTINS.yaml -new file mode 100644 -index 0000000..c8615e3 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ENCODING_BUILTINS.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_ENCODING_BUILTINS -+introduced: 2.0.0 -+default: true -+tags: -+ - encoding-api -+description: > -+ Provide TextEncoder and TextDecoder built-ins (the Encoding API) which allow -+ ECMAScript code to encode and decode text stored in a buffer. Only UTF-8 is -+ currently supported for decoding. -+ -+ DUK_USE_BUFFEROBJECT_SUPPORT is recommended but not required: If it is -+ disabled, TextEncoder will encode to a plain buffer instead of a Uint8Array. -+ TextDecoder always accepts plain buffers as input. -diff --git a/dist/source/config/config-options/DUK_USE_ERRCREATE.yaml b/dist/source/config/config-options/DUK_USE_ERRCREATE.yaml -new file mode 100644 -index 0000000..f579fdf ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ERRCREATE.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_ERRCREATE -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Call Duktape.errCreate() when augmenting an ECMAScript error object -+ being created. -diff --git a/dist/source/config/config-options/DUK_USE_ERRTHROW.yaml b/dist/source/config/config-options/DUK_USE_ERRTHROW.yaml -new file mode 100644 -index 0000000..fdd2b02 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ERRTHROW.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_ERRTHROW -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Call Duktape.errThrow() when augmenting an ECMAScript error object -+ about to be thrown. -diff --git a/dist/source/config/config-options/DUK_USE_ES6.yaml b/dist/source/config/config-options/DUK_USE_ES6.yaml -new file mode 100644 -index 0000000..886fe9b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES6.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ES6 -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Enable ES6 functionality not covered by other specific config options. -diff --git a/dist/source/config/config-options/DUK_USE_ES6_OBJECT_PROTO_PROPERTY.yaml b/dist/source/config/config-options/DUK_USE_ES6_OBJECT_PROTO_PROPERTY.yaml -new file mode 100644 -index 0000000..d0279d4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES6_OBJECT_PROTO_PROPERTY.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ES6_OBJECT_PROTO_PROPERTY -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Provide the non-standard (ES6) Object.prototype.__proto__ property. -diff --git a/dist/source/config/config-options/DUK_USE_ES6_OBJECT_SETPROTOTYPEOF.yaml b/dist/source/config/config-options/DUK_USE_ES6_OBJECT_SETPROTOTYPEOF.yaml -new file mode 100644 -index 0000000..04b29fb ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES6_OBJECT_SETPROTOTYPEOF.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ES6_OBJECT_SETPROTOTYPEOF -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Provide the non-standard (ES6) Object.setPrototypeOf method. -diff --git a/dist/source/config/config-options/DUK_USE_ES6_PROXY.yaml b/dist/source/config/config-options/DUK_USE_ES6_PROXY.yaml -new file mode 100644 -index 0000000..e05952c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES6_PROXY.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ES6_PROXY -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Provide the non-standard (ES6) Proxy object. -diff --git a/dist/source/config/config-options/DUK_USE_ES6_REGEXP_BRACES.yaml b/dist/source/config/config-options/DUK_USE_ES6_REGEXP_BRACES.yaml -new file mode 100644 -index 0000000..ea864f8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES6_REGEXP_BRACES.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_ES6_REGEXP_BRACES -+introduced: 1.5.0 -+removed: 2.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Replaced by DUK_USE_ES6_REGEXP_SYNTAX. -diff --git a/dist/source/config/config-options/DUK_USE_ES6_REGEXP_SYNTAX.yaml b/dist/source/config/config-options/DUK_USE_ES6_REGEXP_SYNTAX.yaml -new file mode 100644 -index 0000000..f9f1c41 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES6_REGEXP_SYNTAX.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_ES6_REGEXP_SYNTAX -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Enable support for additional RegExp syntax from E6 Section B.1.4, such as: -+ (1) dollar escape, (2) unescaped curly braces ('{' and '}'), and (3) -+ unescaped right bracket (']'). This option does not enable all of the ES6 -+ syntax because not all of the extra syntax is implemented; rather, the option -+ enables whatever ES6 extra syntax has been implemented so far. -+ -+ This option is recommended because a lot of existing code depends on literal -+ regexp braces, and other non-ES5 constructs. -diff --git a/dist/source/config/config-options/DUK_USE_ES6_UNICODE_ESCAPE.yaml b/dist/source/config/config-options/DUK_USE_ES6_UNICODE_ESCAPE.yaml -new file mode 100644 -index 0000000..5ed1cb4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES6_UNICODE_ESCAPE.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_ES6_UNICODE_ESCAPE -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Enable support for ES6 Unicode escape syntax ("\u{12345}") in source code -+ and RegExps. -diff --git a/dist/source/config/config-options/DUK_USE_ES7.yaml b/dist/source/config/config-options/DUK_USE_ES7.yaml -new file mode 100644 -index 0000000..e195be3 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES7.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ES7 -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2016 -+description: > -+ Enable ES7 functionality not covered by other specific config options. -diff --git a/dist/source/config/config-options/DUK_USE_ES7_EXP_OPERATOR.yaml b/dist/source/config/config-options/DUK_USE_ES7_EXP_OPERATOR.yaml -new file mode 100644 -index 0000000..8cd9fe4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES7_EXP_OPERATOR.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_ES7_EXP_OPERATOR -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2016 -+description: > -+ Support the ES7 exponentiation operator (** and **=). This is optional -+ because the operator pulls in pow() which may have a significant footprint -+ impact on bare metal platforms. -diff --git a/dist/source/config/config-options/DUK_USE_ES8.yaml b/dist/source/config/config-options/DUK_USE_ES8.yaml -new file mode 100644 -index 0000000..ec10b5c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES8.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ES8 -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2017 -+description: > -+ Enable ES8 functionality not covered by other specific config options. -diff --git a/dist/source/config/config-options/DUK_USE_ES9.yaml b/dist/source/config/config-options/DUK_USE_ES9.yaml -new file mode 100644 -index 0000000..541a00d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ES9.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ES9 -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2018 -+description: > -+ Enable ES9 functionality not covered by other specific config options. -diff --git a/dist/source/config/config-options/DUK_USE_ESBC_LIMITS.yaml b/dist/source/config/config-options/DUK_USE_ESBC_LIMITS.yaml -new file mode 100644 -index 0000000..b96de7a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ESBC_LIMITS.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_ESBC_LIMITS -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Impose byte and line number limits for compiled function bytecode. -diff --git a/dist/source/config/config-options/DUK_USE_ESBC_MAX_BYTES.yaml b/dist/source/config/config-options/DUK_USE_ESBC_MAX_BYTES.yaml -new file mode 100644 -index 0000000..1230861 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ESBC_MAX_BYTES.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_ESBC_MAX_BYTES -+introduced: 1.0.0 -+requires: -+ - DUK_USE_ESBC_LIMITS -+default: 0x7fff0000 -+tags: -+ - ecmascript -+description: > -+ Maximum byte count for compiled function bytecode. -diff --git a/dist/source/config/config-options/DUK_USE_ESBC_MAX_LINENUMBER.yaml b/dist/source/config/config-options/DUK_USE_ESBC_MAX_LINENUMBER.yaml -new file mode 100644 -index 0000000..6f1da17 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ESBC_MAX_LINENUMBER.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_ESBC_MAX_LINENUMBER -+introduced: 1.0.0 -+requires: -+ - DUK_USE_ESBC_LIMITS -+default: 0x7fff0000 -+tags: -+ - ecmascript -+description: > -+ Maximum line number for compiled function bytecode. -diff --git a/dist/source/config/config-options/DUK_USE_EXAMPLE.yaml b/dist/source/config/config-options/DUK_USE_EXAMPLE.yaml -new file mode 100644 -index 0000000..7fa5959 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXAMPLE.yaml -@@ -0,0 +1,74 @@ -+# -+# Each Duktape option is described as a YAML file named OPTION_NAME.yaml. -+# YAML is used because it diffs well and has clean support for multiline -+# inline strings. -+# -+ -+# C #define name for the option. Must match filename minus extension. -+define: DUK_USE_OBJSIZES16 -+ -+# Duktape version number where this option was first introduced. -+introduced: 1.1.0 -+ -+# Optional Duktape version number where this option was deprecated, -+# i.e. the option is supported but no longer recommended. -+# XXX: automatic #error with some -DDUK_USE_NO_DEPRECATED flag? -+#deprecated: 1.2.0 -+ -+# Optional Duktape version number where this option was removed, -+# i.e. the option is no longer supported but we may want to issue -+# a clear #error for it. -+#removed: 1.3.0 -+ -+# Optional indication that config option is defined but currently -+# unused, so that it can be omitted from generated header. -+#unused: true -+ -+# Optional list of options that must also be defined to use this option. -+#requires: -+# - DUK_USE_FOO -+# - DUK_USE_BAR -+ -+# Optional list of options that this option conflicts with. -+#conflicts: -+# - DUK_USE_BAZ -+ -+# Optional list of options that are related from a user and documentation -+# perspective. -+#related: -+# - DUK_USE_QUUX -+ -+# Default value for option: -+# - false: undefined (#undef DUK_USE_EXAMPLE) -+# - true: defined with no value (#define DUK_USE_EXAMPLE) -+# - string: defined with string value (#define DUK_USE_EXAMPLE "foo") -+# - number: defined with number value (#define DUK_USE_EXAMPLE 123) -+# - verbatim: define verbatim line(s) -+default: false -+ -+# Tags related to option (required). If present, first tag is used as a -+# primary tag for grouping. Use 'misc' if nothing else is appropriate. -+tags: -+ - lowmemory -+ - experimental -+ -+# When set to true, genconfig.py will warn if no forced value is provided. -+# This should be used sparingly, for options which are really strongly -+# recommended so that configure.py output should warn about it. -+#warn_if_missing: true -+ -+# Description for option, no newlines. Line breaking for e.g. C header -+# is automatic. -+description: > -+ Use a 16-bit object entry and array part sizes (for low memory -+ environments). Also automatically drops support for an object hash -+ part to further reduce memory usage; there are rarely large objects -+ in low memory environments simply because there's no memory to store -+ a lot of properties. -+ -+ By default use "description: >" markup which works well for paragraphs -+ (replacing newlines with spaces) but includes a trailing newline which -+ is also a good default. -+ -+# Marker to avoid processing this file. -+example: true -diff --git a/dist/source/config/config-options/DUK_USE_EXEC_FUN_LOCAL.yaml b/dist/source/config/config-options/DUK_USE_EXEC_FUN_LOCAL.yaml -new file mode 100644 -index 0000000..3d66df2 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXEC_FUN_LOCAL.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_EXEC_FUN_LOCAL -+introduced: 1.4.0 -+default: false -+tags: -+ - performance -+ - execution -+description: > -+ Use a local variable "fun" pointing to the current function in the bytecode -+ dispatch loop instead of looking up the current function through "thr" every -+ time it is needed. On x64 performance is slightly better without a "fun" -+ local; on x86 performance is slightly better with one. -+ -+ You should only tweak this if you're really interested in performance, and -+ should then do proper testing to see which value works better. -diff --git a/dist/source/config/config-options/DUK_USE_EXEC_INDIRECT_BOUND_CHECK.yaml b/dist/source/config/config-options/DUK_USE_EXEC_INDIRECT_BOUND_CHECK.yaml -new file mode 100644 -index 0000000..16c30f0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXEC_INDIRECT_BOUND_CHECK.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_EXEC_INDIRECT_BOUND_CHECK -+introduced: 1.0.0 -+default: false -+tags: -+ - execution -+ - debug -+description: > -+ For opcodes with indirect indices, check final index against stack size. -+ Useful for diagnosing problems. Normally this check is not necessary -+ because the compiler is trusted, and we don't bound check direct indices -+ either. -diff --git a/dist/source/config/config-options/DUK_USE_EXEC_PREFER_SIZE.yaml b/dist/source/config/config-options/DUK_USE_EXEC_PREFER_SIZE.yaml -new file mode 100644 -index 0000000..19aa8f1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXEC_PREFER_SIZE.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_EXEC_PREFER_SIZE -+introduced: 2.0.0 -+default: false -+tags: -+ - lowmemory -+description: > -+ Prefer size over performance in bytecode executor. -diff --git a/dist/source/config/config-options/DUK_USE_EXEC_REGCONST_OPTIMIZE.yaml b/dist/source/config/config-options/DUK_USE_EXEC_REGCONST_OPTIMIZE.yaml -new file mode 100644 -index 0000000..b7bee88 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXEC_REGCONST_OPTIMIZE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_EXEC_REGCONST_OPTIMIZE -+introduced: 2.0.0 -+default: true -+tags: -+ - performance -+ - execution -+description: > -+ Use an internal optimization to access registers and constants in the -+ bytecode executor. The optimization avoids unnecessary shifts when computing -+ addresses but assumes sizeof(duk_tval) is 8 or 16. This is almost always the -+ case, but when it isn't, disable this option. -diff --git a/dist/source/config/config-options/DUK_USE_EXEC_TIMEOUT_CHECK.yaml b/dist/source/config/config-options/DUK_USE_EXEC_TIMEOUT_CHECK.yaml -new file mode 100644 -index 0000000..27e3e6f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXEC_TIMEOUT_CHECK.yaml -@@ -0,0 +1,31 @@ -+define: DUK_USE_EXEC_TIMEOUT_CHECK -+introduced: 1.2.0 -+requires: -+ - DUK_USE_INTERRUPT_COUNTER -+default: false -+tags: -+ - execution -+ - sandbox -+ - experimental -+description: > -+ NOTE: This mechanism is EXPERIMENTAL and the details may change -+ between releases. -+ -+ Provide a hook to check for bytecode execution timeout. The macro gets -+ a void ptr userdata argument (the userdata given to duk_heap_create()) -+ and must evaluate to a duk_bool_t. Duktape calls the macro as: -+ "if (DUK_USE_EXEC_TIMEOUT_CHECK(udata)) { ... }". -+ -+ The macro is called occasionally by the Duktape bytecode executor (i.e. -+ when executing ECMAScript code), typically from a few times per second -+ to a hundred times per second, but the interval varies a great deal -+ depending on what kind of code is being executed. -+ -+ To indicate an execution timeout, the macro must return a non-zero value. -+ When that happens, Duktape starts to bubble a ``RangeError`` outwards -+ until control has been returned to the original protected call made by -+ the application. Until that happens, the exec timeout macro must always -+ return non-zero to indicate an execution timeout is still in progress. -+ -+ This mechanism and its limitations is described in more detail in -+ doc/sandboxing.rst. -diff --git a/dist/source/config/config-options/DUK_USE_EXPLICIT_NULL_INIT.yaml b/dist/source/config/config-options/DUK_USE_EXPLICIT_NULL_INIT.yaml -new file mode 100644 -index 0000000..0da6c1b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXPLICIT_NULL_INIT.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_EXPLICIT_NULL_INIT -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ When zeroing structures, don't rely on memzero initializing pointers to -+ NULL. Instead, write NULL values explicitly after zeroing. This should -+ only be necessary when a NULL pointer is not represented by zero bytes in -+ memory. -+ -+ # NOTE: Condition in Duktape 1.2 seems wrong, and is linked to packed tval. -diff --git a/dist/source/config/config-options/DUK_USE_EXTSTR_FREE.yaml b/dist/source/config/config-options/DUK_USE_EXTSTR_FREE.yaml -new file mode 100644 -index 0000000..d8c2972 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXTSTR_FREE.yaml -@@ -0,0 +1,23 @@ -+define: DUK_USE_EXTSTR_FREE -+introduced: 1.1.0 -+requires: -+ - DUK_USE_HSTRING_EXTDATA -+default: false -+tags: -+ - memory -+ - experimental -+description: > -+ Optional counterpart to DUK_USE_EXTSTR_INTERN_CHECK. Invoked when an -+ external string is about to be freed by Duktape. -+ -+ The argument "ptr" is a void ptr and points to the external string data. -+ Concretely, it is the (non-NULL) value returned by -+ DUK_USE_EXTSTR_INTERN_CHECK. The "udata" argument is the heap userdata -+ which may be ignored if not needed. -+ -+ Also enable DUK_USE_HSTRING_EXTDATA to use this feature. -+ -+ NOTE: Right now there is no API to push external strings; external strings -+ come into being as a result of DUK_USE_EXTSTR_INTERN_CHECK() only. If/when -+ this is changed, this hook will get called for every string, even if pushed -+ by the user using an API call; this may need to be rethought at that time. -diff --git a/dist/source/config/config-options/DUK_USE_EXTSTR_INTERN_CHECK.yaml b/dist/source/config/config-options/DUK_USE_EXTSTR_INTERN_CHECK.yaml -new file mode 100644 -index 0000000..784eb25 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_EXTSTR_INTERN_CHECK.yaml -@@ -0,0 +1,39 @@ -+define: DUK_USE_EXTSTR_INTERN_CHECK -+introduced: 1.1.0 -+requires: -+ - DUK_USE_HSTRING_EXTDATA -+default: false -+tags: -+ - memory -+ - experimental -+description: > -+ Provide a hook for checking if data for a certain string can be used from -+ external memory (outside of Duktape heap, e.g. memory mapped flash). -+ The hook is called during string interning with the following semantics: -+ -+ The string data with no NUL termination resides at "ptr" and has "len" -+ bytes. The "udata" argument is the heap userdata which may be ignored -+ if not needed. If the hook returns NULL, Duktape interns the string -+ normally, i.e. string data is allocated from Duktape heap. Otherwise the -+ hook return value must point to a memory area which contains -+ "len" bytes from "ptr" followed by a NUL byte which is NOT PRESENT -+ in the input data. Data behind the returned pointer may not change after -+ the hook returns. -+ -+ The hook may be called several times for the same input string. This -+ happens when a string is interned, garbage collected, and then interned -+ again. -+ -+ The DUK_USE_EXTSTR_FREE() hook allows application code to detect when -+ an external string is about to be freed. -+ -+ In most cases the hook should reject strings whose "len" is less than 4 -+ because there is no RAM advantage in moving so short strings into external -+ memory. The ordinary "duk_hstring" header followed by the data (and a -+ NUL byte) has the same size as "duk_hstring_external" header which hosts -+ a pointer instead of string data. -+ -+ Also enable DUK_USE_HSTRING_EXTDATA to use this feature. -+ -+ See doc/low-memory.rst for more discussion how to use this feature option -+ in practice. -diff --git a/dist/source/config/config-options/DUK_USE_FASTINT.yaml b/dist/source/config/config-options/DUK_USE_FASTINT.yaml -new file mode 100644 -index 0000000..8726026 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FASTINT.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_FASTINT -+requires: -+ - DUK_USE_64BIT_OPS -+introduced: 1.2.0 -+default: false -+tags: -+ - performance -+ - fastpath -+description: > -+ Enable support for 48-bit signed "fastint" integer values. Fastints are -+ transparent to user code (both C and ECMAScript) but may be faster than -+ IEEE doubles on some platforms, especially those using softints. The -+ downside of fastints is increased code footprint and a small performance -+ penalty for some kinds of code. -diff --git a/dist/source/config/config-options/DUK_USE_FAST_REFCOUNT_DEFAULT.yaml b/dist/source/config/config-options/DUK_USE_FAST_REFCOUNT_DEFAULT.yaml -new file mode 100644 -index 0000000..bc9b2f9 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FAST_REFCOUNT_DEFAULT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_FAST_REFCOUNT_DEFAULT -+introduced: 1.2.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - experimental -+description: > -+ When enabled, plain refcount macros (e.g. DUK_TVAL_INCREF) default to -+ fast variants (DUK_TVAL_INCREF_FAST) to improve performance. -diff --git a/dist/source/config/config-options/DUK_USE_FATAL_HANDLER.yaml b/dist/source/config/config-options/DUK_USE_FATAL_HANDLER.yaml -new file mode 100644 -index 0000000..e53c914 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FATAL_HANDLER.yaml -@@ -0,0 +1,23 @@ -+define: DUK_USE_FATAL_HANDLER -+introduced: 2.0.0 -+default: false -+tags: -+ - portability -+warn_if_missing: true -+description: > -+ Provide a custom default fatal error handler to replace the built-in one -+ (which calls abort() without any error message). The default fatal error -+ handler gets called when (1) a fatal error occurs and application code -+ didn't register a fatal error handler in heap creation or (2) a context-free -+ fatal error happens, concretely e.g. an assertion failure. -+ -+ The handler is called like a C function with the prototype -+ "void fatal_handler(void *udata, const char *msg)". The "msg" argument can -+ be NULL. The "udata" argument matches the heap-related userdata but is -+ NULL for fatal errors unrelated to a heap/thread context (this is the case -+ for e.g. assertions). -+ -+ A custom default fatal error handler is recommended for any environment -+ where recover from fatal errors is important. A custom handler can take -+ appropriate action to recover, e.g. record the error and reboot the target -+ device. -diff --git a/dist/source/config/config-options/DUK_USE_FATAL_MAXLEN.yaml b/dist/source/config/config-options/DUK_USE_FATAL_MAXLEN.yaml -new file mode 100644 -index 0000000..2971c20 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FATAL_MAXLEN.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_FATAL_MAXLEN -+introduced: 2.2.0 -+default: 128 -+tags: -+ - portability -+description: > -+ Maximum length of fatal error message string when error is thrown by -+ Duktape internals, in particular for uncaught errors. -diff --git a/dist/source/config/config-options/DUK_USE_FILE_IO.yaml b/dist/source/config/config-options/DUK_USE_FILE_IO.yaml -new file mode 100644 -index 0000000..8ff767d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FILE_IO.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_FILE_IO -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - io -+description: > -+ File I/O support. This is now used in a few API calls to e.g. push -+ a string from file contents or eval a file. For portability it must -+ be possible to disable I/O altogether. -diff --git a/dist/source/config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml -new file mode 100644 -index 0000000..1bb8694 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_FINALIZER_SUPPORT -+introduced: 2.0.0 -+default: true -+tags: -+ - execution -+description: > -+ Enable support for object finalizers (Duktape specific). -diff --git a/dist/source/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml b/dist/source/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml -new file mode 100644 -index 0000000..30b32b7 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FINALIZER_TORTURE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_FINALIZER_TORTURE -+introduced: 2.1.0 -+default: false -+tags: -+ - gc -+ - memory -+ - development -+ - torture -+description: > -+ Development time option: simulate a fake finalizer call every time when -+ finalizers might be executed (even if the actual finalize_list is empty). -diff --git a/dist/source/config/config-options/DUK_USE_FLEX_C99.yaml b/dist/source/config/config-options/DUK_USE_FLEX_C99.yaml -new file mode 100644 -index 0000000..7ade513 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FLEX_C99.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_FLEX_C99 -+introduced: 1.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Use C99 flexible array member for defining variable size structures. -+ -+# XXX: currently unused, remove or mark unused so doesn't get emitted? -diff --git a/dist/source/config/config-options/DUK_USE_FLEX_ONESIZE.yaml b/dist/source/config/config-options/DUK_USE_FLEX_ONESIZE.yaml -new file mode 100644 -index 0000000..46894fb ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FLEX_ONESIZE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_FLEX_ONESIZE -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use a single element array to define variable size structures. This is the -+ most portable alternative: zero-size arrays are not allowed by all compilers -+ and flexible array member ("char arr[]") is defined in C99. -+ -+# XXX: currently unused, remove or mark unused so doesn't get emitted? -diff --git a/dist/source/config/config-options/DUK_USE_FLEX_ZEROSIZE.yaml b/dist/source/config/config-options/DUK_USE_FLEX_ZEROSIZE.yaml -new file mode 100644 -index 0000000..2d4f756 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FLEX_ZEROSIZE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_FLEX_ZEROSIZE -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use a zero element array to define variable size structures. This is not -+ fully portable but works with some compilers and is preferred over using -+ a one element array. -+ -+# XXX: currently unused, remove or mark unused so doesn't get emitted? -diff --git a/dist/source/config/config-options/DUK_USE_FULL_TVAL.yaml b/dist/source/config/config-options/DUK_USE_FULL_TVAL.yaml -new file mode 100644 -index 0000000..796c317 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FULL_TVAL.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_FULL_TVAL -+introduced: 1.0.0 -+removed: 1.2.0 -+default: false -+tags: -+ - misc -+description: > -+ Initialize all bytes of a duk_tval when setting a value into one. -+ -+ By default only needed fields are initialized which reduces code size and -+ improves performance slightly. This should cause no functional issues but -+ may cause valgrind issues in rare cases, e.g. when debugger code dumps the -+ constant table of a function (which then reads uninitialized bits). -+ -+ Removed in 1.2.0 because the option was never enabled and there was no -+ feature option to cause it to be used. -diff --git a/dist/source/config/config-options/DUK_USE_FUNCPTR16.yaml b/dist/source/config/config-options/DUK_USE_FUNCPTR16.yaml -new file mode 100644 -index 0000000..bf54cdb ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FUNCPTR16.yaml -@@ -0,0 +1,21 @@ -+define: DUK_USE_FUNCPTR16 -+introduced: 1.1.0 -+related: -+ - DUK_USE_FUNCPTR_ENC16 -+ - DUK_USE_FUNCPTR_DEC16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable "compression" of arbitrary data pointers into an unsigned 16-bit -+ value. Use together with DUK_USE_DATAPTR_ENC16 and DUK_USE_DATAPTR_DEC16. -+ -+ Pointers compressed are any void pointers in C code, not just the Duktape -+ heap. Also NULL pointer must encode and decode correctly. -+ -+ Currently it is required that NULL encodes to integer 0, and integer -+ 0 decodes to NULL. No other pointer can be encoded to 0. -+ -+ NOTE: This feature option is currently unimplemented, i.e. Duktape won't -+ compress any data pointers at the moment. -diff --git a/dist/source/config/config-options/DUK_USE_FUNCPTR_DEC16.yaml b/dist/source/config/config-options/DUK_USE_FUNCPTR_DEC16.yaml -new file mode 100644 -index 0000000..f1e10c0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FUNCPTR_DEC16.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_FUNCPTR_DEC16 -+introduced: 1.1.0 -+requires: -+ - DUK_USE_FUNCPTR16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_USE_FUNCPTR16 for arbitrary data pointer compression. -+ DUK_USE_FUNCPTR_ENC16(udata,p) is a macro with a userdata and void ptr -+ argument, and a duk_uint16_t return value. The userdata argument is the -+ heap userdata value given at heap creation. Currently it is required that -+ NULL encodes to integer 0, and integer 0 decodes to NULL. No other pointer -+ can be encoded to 0. -diff --git a/dist/source/config/config-options/DUK_USE_FUNCPTR_ENC16.yaml b/dist/source/config/config-options/DUK_USE_FUNCPTR_ENC16.yaml -new file mode 100644 -index 0000000..51ff363 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FUNCPTR_ENC16.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_FUNCPTR_ENC16 -+introduced: 1.1.0 -+requires: -+ - DUK_USE_FUNCPTR16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_USE_FUNCPTR16 for arbitrary data pointer compression. -+ DUK_USE_FUNCPTR_DEC16(udata,x) is a macro with a userdata and duk_uint16_t -+ argument, and a void ptr return value. The userdata argument is the heap -+ userdata value given at heap creation. -diff --git a/dist/source/config/config-options/DUK_USE_FUNCTION_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_FUNCTION_BUILTIN.yaml -new file mode 100644 -index 0000000..663cd45 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FUNCTION_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_FUNCTION_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide a Function built-in. -diff --git a/dist/source/config/config-options/DUK_USE_FUNC_FILENAME_PROPERTY.yaml b/dist/source/config/config-options/DUK_USE_FUNC_FILENAME_PROPERTY.yaml -new file mode 100644 -index 0000000..74e98bd ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FUNC_FILENAME_PROPERTY.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_FUNC_FILENAME_PROPERTY -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Add a non-standard ".fileName" property to function instances. Disabling -+ reduces footprint. -diff --git a/dist/source/config/config-options/DUK_USE_FUNC_NAME_PROPERTY.yaml b/dist/source/config/config-options/DUK_USE_FUNC_NAME_PROPERTY.yaml -new file mode 100644 -index 0000000..fce6625 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FUNC_NAME_PROPERTY.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_FUNC_NAME_PROPERTY -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Add a "name" property to function instances. This is part of ECMAScript -+ requirements, but low memory devices can sometimes opt to not include the -+ .name to reduce footprint. -diff --git a/dist/source/config/config-options/DUK_USE_FUZZILLI.yaml b/dist/source/config/config-options/DUK_USE_FUZZILLI.yaml -new file mode 100644 -index 0000000..baf88d0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_FUZZILLI.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_FUZZILLI -+introduced: 3.0.0 -+default: false -+tags: -+ - fuzzing -+description: > -+ Needed when running Fuzzilli fuzzing, enables access to duk_assert_wrapper() -+ expected by the integration. -diff --git a/dist/source/config/config-options/DUK_USE_GCC_PRAGMAS.yaml b/dist/source/config/config-options/DUK_USE_GCC_PRAGMAS.yaml -new file mode 100644 -index 0000000..9a68e46 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GCC_PRAGMAS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_GCC_PRAGMAS -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use GCC-specific pragmas, e.g. "#pragma GCC diagnostic" to suppress -+ unnecessary warnings. -diff --git a/dist/source/config/config-options/DUK_USE_GC_TORTURE.yaml b/dist/source/config/config-options/DUK_USE_GC_TORTURE.yaml -new file mode 100644 -index 0000000..7f2968a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GC_TORTURE.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_GC_TORTURE -+introduced: 1.0.0 -+default: false -+tags: -+ - gc -+ - memory -+ - development -+ - torture -+description: > -+ Development time option: force full mark-and-sweep on every allocation and -+ in other chosen places to stress test memory management. -+ -+ Using a low value (e.g. 3) for DUK_USE_MARK_AND_SWEEP_RECLIMIT is also -+ recommended. -diff --git a/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml b/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml -new file mode 100644 -index 0000000..d5ed7b3 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME.yaml -@@ -0,0 +1,22 @@ -+define: DUK_USE_GET_MONOTONIC_TIME -+introduced: 2.2.0 -+default: false -+tags: -+ - portability -+description: > -+ Optional macro for getting monotonic time in milliseconds from an arbitrary -+ starting point (device startup, program startup, script startup, etc). -+ Fractional time values are allowed (and even recommended). The time returned -+ must increase monotonically, and must not jump discontinuously even if system -+ date/time is reset. The semantics are similar to POSIX clock_gettime() -+ CLOCK_MONOTONIC. -+ -+ Monotonic time is used by Duktape for its internal needs, such as rate -+ limiting debugger transport peek callbacks. It is also used to provide -+ performance.now(). If this option is not provided, Duktape falls back to -+ using DUK_USE_DATE_GET_NOW() which is usually fine. -+ -+ If DUK_USE_DATE_GET_NOW() experiences time jumps or doesn't run in realtime -+ (which may be useful for some time virtualization cases) it's recommended -+ to provide this config option so that internals which need a reliable -+ realtime rate have a reliable time basis. -diff --git a/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME.yaml b/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME.yaml -new file mode 100644 -index 0000000..8f18392 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME -+introduced: 2.2.0 -+default: false -+tags: -+ - portability -+description: > -+ Use clock_gettime(CLOCK_MONOTONIC, ...) for monotonic time on POSIX -+ platforms. -diff --git a/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC.yaml b/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC.yaml -new file mode 100644 -index 0000000..ca5bc19 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC -+introduced: 2.2.0 -+default: false -+tags: -+ - portability -+description: > -+ Use QueryPerformanceCounter() for monotonic time on Windows. -diff --git a/dist/source/config/config-options/DUK_USE_GET_RANDOM_DOUBLE.yaml b/dist/source/config/config-options/DUK_USE_GET_RANDOM_DOUBLE.yaml -new file mode 100644 -index 0000000..2ae1c20 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GET_RANDOM_DOUBLE.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_GET_RANDOM_DOUBLE -+introduced: 2.0.0 -+default: false -+tags: -+ - portability -+ - performance -+description: > -+ Override the default internal random number generator which is used for -+ Math.random() and some other internal call sites (currently, for example, -+ Array.prototype.sort()). The default random number generator has a very -+ low footprint but is not suitable for serious statistics algorithms or -+ cryptography. Overriding the random number generator may thus be useful -+ in some environments. -+ -+ The macro gets a heap userdata argument and must provide an IEEE double -+ in the range [0,1[. -diff --git a/dist/source/config/config-options/DUK_USE_GLOBAL_BINDING.yaml b/dist/source/config/config-options/DUK_USE_GLOBAL_BINDING.yaml -new file mode 100644 -index 0000000..55b357f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GLOBAL_BINDING.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_GLOBAL_BINDING -+introduced: 2.1.0 -+default: true -+tags: -+ - ecmascript -+ - experimental -+description: > -+ Provide a 'globalThis' binding (https://github.com/tc39/proposal-global). -diff --git a/dist/source/config/config-options/DUK_USE_GLOBAL_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_GLOBAL_BUILTIN.yaml -new file mode 100644 -index 0000000..b8ba6e4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_GLOBAL_BUILTIN.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_GLOBAL_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide miscellaneous global built-ins like encodeURIComponent(), escape(), -+ Infinity, etc. This is a catch-all for globals not covered by other options -+ (like DUK_USE_ARRAY_BUILTIN). -diff --git a/dist/source/config/config-options/DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS.yaml b/dist/source/config/config-options/DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS.yaml -new file mode 100644 -index 0000000..fe5e336 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Allow unaligned 32-bit unsigned integer access in hashbytes algorithm. -diff --git a/dist/source/config/config-options/DUK_USE_HEAPPTR16.yaml b/dist/source/config/config-options/DUK_USE_HEAPPTR16.yaml -new file mode 100644 -index 0000000..608143f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HEAPPTR16.yaml -@@ -0,0 +1,35 @@ -+define: DUK_USE_HEAPPTR16 -+introduced: 1.1.0 -+conflicts: -+ - DUK_USE_DEBUG -+related: -+ - DUK_USE_HEAPPTR_ENC16 -+ - DUK_USE_HEAPPTR_DEC16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable "compression" of Duktape heap pointers into an unsigned 16-bit value. -+ Use together with DUK_USE_HEAPPTR_ENC16 and DUK_USE_HEAPPTR_DEC16. -+ -+ Pointers compressed are those allocated from Duktape heap, using the user -+ provided allocation functions. Also NULL pointer must encode and decode -+ correctly. -+ -+ Currently it is required that NULL encodes to integer 0, and integer -+ 0 decodes to NULL. No other pointer can be encoded to 0. -+ -+ This option reduces memory usage by several kilobytes, but has several -+ downsides. It can only be applied when Duktape heap is limited in size, -+ for instance, with 4-byte aligned allocations a 256kB heap (minus one value -+ for NULL) can be supported. Pointer encoding and decoding may be relatively -+ complicated as they need to correctly handle NULL pointers and -+ non-continuous memory maps used by some targets. The macro may need to call -+ out to a helper function in practice, which is much slower than an inline -+ implementation. -+ -+ Current limitation: Duktape internal debug code enabled with e.g. -+ DUK_USE_DEBUG and DUK_USE_DEBUG_LEVEL=0 doesn't have enough plumbing to be -+ able to decode pointers. Debug printing cannot currently be enabled when -+ pointer compression is active. -diff --git a/dist/source/config/config-options/DUK_USE_HEAPPTR_DEC16.yaml b/dist/source/config/config-options/DUK_USE_HEAPPTR_DEC16.yaml -new file mode 100644 -index 0000000..1262dca ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HEAPPTR_DEC16.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_HEAPPTR_DEC16 -+introduced: 1.1.0 -+requires: -+ - DUK_USE_HEAPPTR16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_USE_HEAPPTR16 for heap pointer compression. -+ DUK_USE_HEAPPTR_DEC16(udata,x) is a macro with a userdata and duk_uint16_t -+ argument, and a void ptr return value. The userdata argument is the heap -+ userdata value given at heap creation. -diff --git a/dist/source/config/config-options/DUK_USE_HEAPPTR_ENC16.yaml b/dist/source/config/config-options/DUK_USE_HEAPPTR_ENC16.yaml -new file mode 100644 -index 0000000..7339c49 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HEAPPTR_ENC16.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_HEAPPTR_ENC16 -+introduced: 1.1.0 -+requires: -+ - DUK_USE_HEAPPTR16 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_USE_HEAPPTR16 for heap pointer compression. -+ DUK_USE_HEAPPTR_ENC16(udata,p) is a macro with a userdata and void ptr -+ argument, and a duk_uint16_t return value. The userdata argument is the -+ heap userdata value given at heap creation. -diff --git a/dist/source/config/config-options/DUK_USE_HEX_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_HEX_FASTPATH.yaml -new file mode 100644 -index 0000000..c00bbe4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HEX_FASTPATH.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_HEX_FASTPATH -+introduced: 1.4.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for hex encode/decode. The fast path uses a lookup -+ table at a small cost in footprint. -diff --git a/dist/source/config/config-options/DUK_USE_HEX_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_HEX_SUPPORT.yaml -new file mode 100644 -index 0000000..9cc26b5 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HEX_SUPPORT.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_HEX_SUPPORT -+introduced: 2.3.0 -+default: true -+tags: -+ - codec -+description: > -+ Enable hex encoding/decoding support. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml -new file mode 100644 -index 0000000..2e72af2 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT -+introduced: 2.1.0 -+default: 2 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Abandon array part if its density is below L and array is larger than -+ DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE. The limit L is expressed as -+ a .3 fixed point point, e.g. 2 means 2/8 = 25%. -+ -+ The default limit is quite low: one array entry with packed duk_tval is 8 -+ bytes whereas one normal entry is 4+1+8 = 13 bytes without a hash entry, -+ and 17-21 bytes with a hash entry (load factor 0.5-1.0). So the array part -+ shouldn't be abandoned very easily from a footprint point of view. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE.yaml -new file mode 100644 -index 0000000..4e83aa2 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE -+introduced: 2.5.0 -+default: 257 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Minimum array size required for array to be abandoned. For example, a value -+ of 257 means arrays up to 256 long are never abandoned. The default value -+ ensures 8-bit lookups are not abandoned even if sparse or initialized in -+ random order. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml -new file mode 100644 -index 0000000..6429d4b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT -+introduced: 2.1.0 -+default: 9 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Skip abandon check in object array part resize if new_size < L * old_size. -+ The limit L is expressed as a .3 fixed point value, e.g. 9 means 9/8 = -+ 112.5% of current size. -+ -+ This is rather technical and you should only change the parameter if you've -+ looked at the internals. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml -new file mode 100644 -index 0000000..82e79f7 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_ADD.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_HOBJECT_ARRAY_MINGROW_ADD -+introduced: 2.1.0 -+default: 16 -+tags: -+ - performance -+description: > -+ Technical internal parameter, see sources for details. Only adjust if -+ you've looked at the internals. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml -new file mode 100644 -index 0000000..98fdb29 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR -+introduced: 2.1.0 -+default: 8 -+tags: -+ - performance -+description: > -+ Technical internal parameter, see sources for details. Only adjust if -+ you've looked at the internals. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml -new file mode 100644 -index 0000000..c31b111 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_ADD.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR -+introduced: 2.1.0 -+default: 8 -+tags: -+ - performance -+description: > -+ Technical internal parameter, see sources for details. Only adjust if -+ you've looked at the internals. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml -new file mode 100644 -index 0000000..c38fd8f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_HOBJECT_ENTRY_MINGROW_ADD -+introduced: 2.1.0 -+default: 16 -+tags: -+ - performance -+description: > -+ Technical internal parameter, see sources for details. Only adjust if -+ you've looked at the internals. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml -new file mode 100644 -index 0000000..4e8c82e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PART.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_HOBJECT_HASH_PART -+introduced: 1.1.0 -+default: true -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a hash table for objects that have enough properties. This should be -+ enabled unless the target is very low on memory. -+ -+ If DUK_USE_OBJSIZES16 is defined, this option must not be defined. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml -new file mode 100644 -index 0000000..008b836 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_HASH_PROP_LIMIT.yaml -@@ -0,0 +1,20 @@ -+define: DUK_USE_HOBJECT_HASH_PROP_LIMIT -+introduced: 2.1.0 -+default: 8 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Minimum number of properties needed for a hash part to be included in the -+ object property table. This limit is checked whenever an object is resized. -+ -+ A hash part improves property lookup performance even for small objects, -+ starting from roughly 4 properties. However, this ignores the cost of -+ setting up and managing the hash part, which is offset only if property -+ lookups made through the hash part can offset the setup cost. A hash part -+ is worth it for heavily accessed small objects or large objects (even those -+ accessed quite infrequently). The limit doesn't take into account property -+ access frequency, so it is necessarily a compromise. -+ -+ A lower value improves performance (a value as low a 4-8 can be useful) -+ while a higher value conserves memory. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_1.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_1.yaml -new file mode 100644 -index 0000000..23a6883 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_1.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_HOBJECT_LAYOUT_1 -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use layout variant 1 for object properties. Layout 1 can be used when the -+ target has no alignment restrictions. It is preferable to other layouts -+ because it produces smaller code and provides direct access to property -+ keys. -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_2.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_2.yaml -new file mode 100644 -index 0000000..c467e3b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_2.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_HOBJECT_LAYOUT_2 -+introduced: 1.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Use layout variant 2 for object properties. Layout 2 can be used on any -+ target (including targets with alignment restrictions). -diff --git a/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_3.yaml b/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_3.yaml -new file mode 100644 -index 0000000..23ea315 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HOBJECT_LAYOUT_3.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_HOBJECT_LAYOUT_3 -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use layout variant 3 for object properties. Layout 3 can be used on any -+ target (including targets with alignment restrictions). It's a bit more -+ packed than layout variant 2 but has a bit slower lookups. -diff --git a/dist/source/config/config-options/DUK_USE_HSTRING_ARRIDX.yaml b/dist/source/config/config-options/DUK_USE_HSTRING_ARRIDX.yaml -new file mode 100644 -index 0000000..9b82aab ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HSTRING_ARRIDX.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_HSTRING_ARRIDX -+introduced: 2.0.0 -+default: true -+tags: -+ - lowmemory -+description: > -+ When enabled, duk_hstring stores a precomputed array index (or "not an array -+ index") value related to the string. This reduces code footprint and -+ improves performance a littl ebit. -+ -+ When disabled, duk_hstring has a flag indicating whether it is an array -+ index or not, but the actual value is computed on-the-fly. -diff --git a/dist/source/config/config-options/DUK_USE_HSTRING_CLEN.yaml b/dist/source/config/config-options/DUK_USE_HSTRING_CLEN.yaml -new file mode 100644 -index 0000000..6f4b3c8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HSTRING_CLEN.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_HSTRING_CLEN -+introduced: 1.5.0 -+default: true -+tags: -+ - lowmemory -+ - experimental -+description: > -+ When DUK_USE_STRLEN16 enabled, indicates whether the character length -+ (clen16) field should be actually present (default) or computed on-the-fly. -+ -+ When clen is computed on-the-fly the duk_hstring structure will be 4 bytes -+ smaller (from 10 bytes + 2 bytes padding to 8 bytes) which may be useful for -+ very low memory targets. -diff --git a/dist/source/config/config-options/DUK_USE_HSTRING_EXTDATA.yaml b/dist/source/config/config-options/DUK_USE_HSTRING_EXTDATA.yaml -new file mode 100644 -index 0000000..6598eb8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HSTRING_EXTDATA.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_HSTRING_EXTDATA -+introduced: 1.1.0 -+default: false -+tags: -+ - memory -+description: > -+ Enable support for external strings. An external string requires a Duktape -+ heap allocation to store a minimal string header, with the actual string -+ data being held behind a pointer (similarly to how dynamic buffers work). -+ -+ This option is needed to use DUK_USE_EXTSTR_INTERN_CHECK and/or -+ DUK_USE_EXTSTR_FREE. -diff --git a/dist/source/config/config-options/DUK_USE_HSTRING_LAZY_CLEN.yaml b/dist/source/config/config-options/DUK_USE_HSTRING_LAZY_CLEN.yaml -new file mode 100644 -index 0000000..7a49aed ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HSTRING_LAZY_CLEN.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_HSTRING_LAZY_CLEN -+introduced: 2.2.0 -+default: true -+tags: -+ - performance -+description: > -+ When enabled, duk_hstring charlen is computed only when accessed; because -+ the charlen of most strings is not accessed during their lifetime, this -+ reduces unnecessary charlen calculations. When disabled, charlen is computed -+ during interning which has smaller code footprint at slightly slower charlen -+ handling. -diff --git a/dist/source/config/config-options/DUK_USE_HTML_COMMENTS.yaml b/dist/source/config/config-options/DUK_USE_HTML_COMMENTS.yaml -new file mode 100644 -index 0000000..cd39e80 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_HTML_COMMENTS.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_HTML_COMMENTS -+introduced: 2.1.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Enable ES2015 Annex B.1.3 HTML comment syntax. -diff --git a/dist/source/config/config-options/DUK_USE_IDCHAR_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_IDCHAR_FASTPATH.yaml -new file mode 100644 -index 0000000..4748674 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_IDCHAR_FASTPATH.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_IDCHAR_FASTPATH -+introduced: 1.5.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for identifier start/part tables, which affect lexing and -+ JSON performance slightly at a small cost in footprint. -diff --git a/dist/source/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml b/dist/source/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml -new file mode 100644 -index 0000000..a1db4a9 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_INJECT_HEAP_ALLOC_ERROR.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_INJECT_HEAP_ALLOC_ERROR -+introduced: 2.1.0 -+default: false -+tags: -+ - development -+description: > -+ Force heap allocation to fail, value indicates the desired error position. -diff --git a/dist/source/config/config-options/DUK_USE_INTEGER_BE.yaml b/dist/source/config/config-options/DUK_USE_INTEGER_BE.yaml -new file mode 100644 -index 0000000..662db0b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_INTEGER_BE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_INTEGER_BE -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+conflicts: -+ - DUK_USE_INTEGER_LE -+ - DUK_USE_INTEGER_ME -+tags: -+ - portability -+description: > -+ Integer memory representation is big endian on the target platform. -diff --git a/dist/source/config/config-options/DUK_USE_INTEGER_LE.yaml b/dist/source/config/config-options/DUK_USE_INTEGER_LE.yaml -new file mode 100644 -index 0000000..d3efa21 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_INTEGER_LE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_INTEGER_LE -+introduced: 1.0.0 -+removed: 1.4.0 -+default: true -+conflicts: -+ - DUK_USE_INTEGER_BE -+ - DUK_USE_INTEGER_ME -+tags: -+ - portability -+description: > -+ Integer memory representation is little endian on the target platform. -diff --git a/dist/source/config/config-options/DUK_USE_INTEGER_ME.yaml b/dist/source/config/config-options/DUK_USE_INTEGER_ME.yaml -new file mode 100644 -index 0000000..a1fdc91 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_INTEGER_ME.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_INTEGER_ME -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+conflicts: -+ - DUK_USE_INTEGER_LE -+ - DUK_USE_INTEGER_BE -+tags: -+ - portability -+description: > -+ Integer memory representation is mixed endian on the target platform. -+ -+ This option is unused (and unsupported) because no target platform currently -+ needs this. -diff --git a/dist/source/config/config-options/DUK_USE_INTERRUPT_COUNTER.yaml b/dist/source/config/config-options/DUK_USE_INTERRUPT_COUNTER.yaml -new file mode 100644 -index 0000000..614c7fa ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_INTERRUPT_COUNTER.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_INTERRUPT_COUNTER -+introduced: 1.1.0 -+related: -+ - DUK_USE_DEBUGGER_SUPPORT -+default: false -+tags: -+ - execution -+ - debugger -+description: > -+ Enable the internal bytecode executor periodic interrupt counter. -+ The mechanism is used to implement e.g. execution step limit, custom -+ profiling, and debugger interaction. Enabling the interrupt counter -+ has a small impact on execution performance. -diff --git a/dist/source/config/config-options/DUK_USE_INTERRUPT_DEBUG_FIXUP.yaml b/dist/source/config/config-options/DUK_USE_INTERRUPT_DEBUG_FIXUP.yaml -new file mode 100644 -index 0000000..48d7df9 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_INTERRUPT_DEBUG_FIXUP.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_INTERRUPT_DEBUG_FIXUP -+introduced: 1.4.0 -+default: false -+tags: -+ - development -+description: > -+ For Duktape development only: enable "interrupt fixup" in call handling -+ so that heap->inst_count_exec and heap->inst_count_interrupt can be -+ manually checked to match. Only useful when debugging and/or asserts -+ are enabled. -diff --git a/dist/source/config/config-options/DUK_USE_JC.yaml b/dist/source/config/config-options/DUK_USE_JC.yaml -new file mode 100644 -index 0000000..0bfc818 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JC.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_JC -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Enable support for the JC custom JSON format. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_JSON_BUILTIN.yaml -new file mode 100644 -index 0000000..e858389 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_JSON_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide a JSON built-in. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_DECNUMBER_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_JSON_DECNUMBER_FASTPATH.yaml -new file mode 100644 -index 0000000..fa47c15 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_DECNUMBER_FASTPATH.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_JSON_DECNUMBER_FASTPATH -+introduced: 1.3.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for decoding numbers in JSON.parse(). The fast path uses -+ a lookup table at a small cost in footprint. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_DECSTRING_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_JSON_DECSTRING_FASTPATH.yaml -new file mode 100644 -index 0000000..ed0e31b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_DECSTRING_FASTPATH.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_JSON_DECSTRING_FASTPATH -+introduced: 1.3.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for string decoding in JSON.parse(). The fast path uses -+ a lookup table at a small cost in footprint. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_DEC_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_JSON_DEC_RECLIMIT.yaml -new file mode 100644 -index 0000000..cd07d3c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_DEC_RECLIMIT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_JSON_DEC_RECLIMIT -+introduced: 1.3.0 -+default: 1000 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ Maximum native stack recursion for JSON decoding. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_EATWHITE_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_JSON_EATWHITE_FASTPATH.yaml -new file mode 100644 -index 0000000..49e1b44 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_EATWHITE_FASTPATH.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_JSON_EATWHITE_FASTPATH -+introduced: 1.3.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for eating whitespace in JSON.parse(). The fast path uses -+ a lookup table at a small cost in footprint. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_ENC_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_JSON_ENC_RECLIMIT.yaml -new file mode 100644 -index 0000000..1df0e07 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_ENC_RECLIMIT.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_JSON_ENC_RECLIMIT -+introduced: 1.3.0 -+default: 1000 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ Maximum native stack recursion for JSON encoding. -+ -+ Must be higher than the internal DUK_JSON_ENC_LOOPARRAY define when -+ DUK_USE_JSON_STRINGIFY_FASTPATH is enabled. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_QUOTESTRING_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_JSON_QUOTESTRING_FASTPATH.yaml -new file mode 100644 -index 0000000..e2ee14e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_QUOTESTRING_FASTPATH.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_JSON_QUOTESTRING_FASTPATH -+introduced: 1.3.0 -+default: true -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for string quoting in JSON.stringify(). The fast path uses -+ a lookup table at a small cost in footprint. -diff --git a/dist/source/config/config-options/DUK_USE_JSON_STRINGIFY_FASTPATH.yaml b/dist/source/config/config-options/DUK_USE_JSON_STRINGIFY_FASTPATH.yaml -new file mode 100644 -index 0000000..4d244f6 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_STRINGIFY_FASTPATH.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_JSON_STRINGIFY_FASTPATH -+introduced: 1.3.0 -+default: false -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast path for JSON.stringify() serialization. The fast path is used -+ when there is no "replacer" argument. Indent argument and JX/JC format is -+ supported since Duktape 1.4.0. The fast path increases code footprint by -+ roughly 1.5 kB but is up to 4-5x faster than the slow path. -+ -+ Current limitation: assumes "long long" type exists (and covers duk_int64_t -+ range) and that sprintf() format string "%lld" works for "long long". -diff --git a/dist/source/config/config-options/DUK_USE_JSON_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_JSON_SUPPORT.yaml -new file mode 100644 -index 0000000..f2eca18 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JSON_SUPPORT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_JSON_SUPPORT -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Enable JSON functionality, affects both ECMAScript and C APIs. -+ Note that disabling DUK_USE_JSON_BUILTIN still leaves the C API intact -+ and pulls in the JSON encoding/decoding functionality; disable this -+ option to remove that too. -diff --git a/dist/source/config/config-options/DUK_USE_JX.yaml b/dist/source/config/config-options/DUK_USE_JX.yaml -new file mode 100644 -index 0000000..f037c96 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_JX.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_JX -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Enable support for the JX custom JSON format. -diff --git a/dist/source/config/config-options/DUK_USE_LEXER_SLIDING_WINDOW.yaml b/dist/source/config/config-options/DUK_USE_LEXER_SLIDING_WINDOW.yaml -new file mode 100644 -index 0000000..c213f9f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_LEXER_SLIDING_WINDOW.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_LEXER_SLIDING_WINDOW -+introduced: 1.3.0 -+default: true -+tags: -+ - lowmemory -+description: > -+ Use a sliding window approach for managing the lexer codepoint lookup window -+ (recommended). If disabled, the lexer uses a slower algorithm which has a -+ slightly smaller code and RAM footprint. -diff --git a/dist/source/config/config-options/DUK_USE_LIGHTFUNC_BUILTINS.yaml b/dist/source/config/config-options/DUK_USE_LIGHTFUNC_BUILTINS.yaml -new file mode 100644 -index 0000000..649bdd0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_LIGHTFUNC_BUILTINS.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_LIGHTFUNC_BUILTINS -+introduced: 1.1.0 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Force built-in functions to be lightweight functions. This reduces -+ memory footprint by around 14 kB at the cost of some non-compliant -+ behavior. -diff --git a/dist/source/config/config-options/DUK_USE_LITCACHE_SIZE.yaml b/dist/source/config/config-options/DUK_USE_LITCACHE_SIZE.yaml -new file mode 100644 -index 0000000..b174130 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_LITCACHE_SIZE.yaml -@@ -0,0 +1,27 @@ -+define: DUK_USE_LITCACHE_SIZE -+introduced: 2.3.0 -+default: 256 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Size of the literal cache, which maps C literal memory addresses into -+ pinned duk_hstring heap object addresses. The cache is used when -+ application code calls one of the duk_xxx_literal() API call variants, -+ such as duk_push_literal() or duk_get_prop_literal(), to speed up the -+ string intern check for the literal. In successful cases this caching -+ makes using duk_xxx_literal() almost as fast as using borrowed heap -+ pointers with duk_xxx_heapptr(). -+ -+ When this option is defined, duk_hstrings related to literals encountered -+ in duk_xxx_literal() API calls are automatically pinned between -+ mark-and-sweep rounds. This accomplishes two things. First, it avoids the -+ need for cache invalidation for the literal cache in normal operation between -+ mark-and-sweep rounds. Second, it reduces string table traffic (i.e. freeing -+ and reallocating) for literals which are likely to occur again and again. -+ However, the downside is that some strings that may occur only temporarily -+ will remain pinned until the next mark-and-sweep round. If this matter, you -+ can avoid it by simply using e.g. duk_xxx_string() when dealing with such -+ strings. -+ -+ The literal cache size must be a power of two (2^N). -diff --git a/dist/source/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml b/dist/source/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml -new file mode 100644 -index 0000000..5589bd1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE.yaml -@@ -0,0 +1,17 @@ -+define: DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE -+introduced: 1.3.0 -+removed: 2.1.0 -+related: -+ - DUK_USE_GC_TORTURE -+ - DUK_USE_REFZERO_FINALIZER_TORTURE -+default: false -+tags: -+ - gc -+ - memory -+ - development -+ - torture -+description: > -+ Development time option: simulate a fake finalizer call during every -+ mark-and-sweep round. This is useful to detect bugs caused by finalizer -+ side effects. Most useful when combined with DUK_USE_GC_TORTURE so that -+ potential finalizer side effects are realized on every allocation. -diff --git a/dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP.yaml b/dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP.yaml -new file mode 100644 -index 0000000..534e8d0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP.yaml -@@ -0,0 +1,19 @@ -+define: DUK_USE_MARK_AND_SWEEP -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - gc -+ - memory -+description: > -+ Enable mark-and-sweep garbage collection (recommended). -+ -+ When disabled, only reference counting is used for garbage collection. -+ This reduces code footprint and eliminates garbage collection pauses, but -+ objects participating in unreachable reference cycles won't be collected -+ until the Duktape heap is destroyed. In particular, function instances -+ won't be collected because they're always in a reference cycle with their -+ default prototype object. Unreachable objects are collected if you break -+ reference cycles manually (and are always freed when a heap is destroyed). -+ -+ NOTE: Removed in Duktape 2.0.0 because mark-and-sweep is no longer optional. -diff --git a/dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP_RECLIMIT.yaml -new file mode 100644 -index 0000000..c34d924 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MARK_AND_SWEEP_RECLIMIT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_MARK_AND_SWEEP_RECLIMIT -+introduced: 1.3.0 -+default: 256 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ Mark-and-sweep C recursion depth for marking phase; if reached, -+ mark object as a TEMPROOT and use multi-pass marking (slower but -+ same result). -diff --git a/dist/source/config/config-options/DUK_USE_MATH_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_MATH_BUILTIN.yaml -new file mode 100644 -index 0000000..35dc0be ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MATH_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_MATH_BUILTIN -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide a Math built-in. -diff --git a/dist/source/config/config-options/DUK_USE_MATH_FMAX.yaml b/dist/source/config/config-options/DUK_USE_MATH_FMAX.yaml -new file mode 100644 -index 0000000..bbe8e9a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MATH_FMAX.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_MATH_FMAX -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Assume platform function fmax() is available and works correctly. -+ Some platforms don't have fmax() (it is defined in C99) and on some -+ platforms (e.g. some uclibc environments) it may not be provided even -+ though the compilation environment is nominally C99. -+ -+ Removed in Duktape 2.0.0: if the platform doesn't have fmax(), simply -+ define a replacement for DUK_FMAX(). -diff --git a/dist/source/config/config-options/DUK_USE_MATH_FMIN.yaml b/dist/source/config/config-options/DUK_USE_MATH_FMIN.yaml -new file mode 100644 -index 0000000..dae2d08 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MATH_FMIN.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_MATH_FMIN -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Assume platform function fmin() is available and works correctly. -+ Some platforms don't have fmin() (it is defined in C99) and on some -+ platforms (e.g. some uclibc environments) it may not be provided even -+ though the compilation environment is nominally C99. -+ -+ Removed in Duktape 2.0.0: if the platform doesn't have fmin(), simply -+ define a replacement for DUK_FMIN(). -diff --git a/dist/source/config/config-options/DUK_USE_MATH_ROUND.yaml b/dist/source/config/config-options/DUK_USE_MATH_ROUND.yaml -new file mode 100644 -index 0000000..d5af637 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MATH_ROUND.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_MATH_ROUND -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Assume platform function round() is available and works correctly. -+ Some platforms don't have round() (it is defined in C99) and on some -+ platforms (e.g. some uclibc environments) it may not be provided even -+ though the compilation environment is nominally C99. -+ -+ Removed in Duktape 2.0.0: if the platform doesn't have round(), simply -+ define a replacement for DUK_ROUND(). Currently DUK_ROUND() isn't used -+ at all however. -diff --git a/dist/source/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml b/dist/source/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml -new file mode 100644 -index 0000000..bb1b9a4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_MS_STRINGTABLE_RESIZE.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_MS_STRINGTABLE_RESIZE -+introduced: 1.0.0 -+removed: 2.1.0 -+default: true -+tags: -+ - gc -+ - memory -+description: > -+ Enable forced string intern table resize during mark-and-sweep garbage -+ collection. This is the recommended behavior. -+ -+ It may be useful to disable this option when reference counting is disabled, -+ as mark-and-sweep collections will be more frequent and thus more expensive. -diff --git a/dist/source/config/config-options/DUK_USE_NATIVE_CALL_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_NATIVE_CALL_RECLIMIT.yaml -new file mode 100644 -index 0000000..a27e032 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NATIVE_CALL_RECLIMIT.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_NATIVE_CALL_RECLIMIT -+introduced: 1.3.0 -+default: 1000 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ Maximum duk_handle_call() / duk_handle_safe_call() C recursion limit. -+ Note that this does not limit bytecode executor internal call depth at -+ all (e.g. for ECMAScript-to-ECMAScript calls, thread yields/resumes, etc). -+ There is a separate callstack depth limit for threads which is independent -+ of this limit. -diff --git a/dist/source/config/config-options/DUK_USE_NATIVE_STACK_CHECK.yaml b/dist/source/config/config-options/DUK_USE_NATIVE_STACK_CHECK.yaml -new file mode 100644 -index 0000000..24774c8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NATIVE_STACK_CHECK.yaml -@@ -0,0 +1,22 @@ -+define: DUK_USE_NATIVE_STACK_CHECK -+introduced: 2.4.0 -+default: false -+tags: -+ - portability -+ - execution -+description: > -+ Provide a macro hook to check for available native stack space for the -+ currently executing native thread. The macro must evaluate to zero if -+ there is enough stack space available and non-zero otherwise; a RangeError -+ will then be thrown. -+ -+ The definition of "enough space" depends on the target platform and the -+ compiler because the size of native stack frames cannot be easily known -+ in advance. As a relatively safe estimate, one can check for 8kB of -+ available stack. -+ -+ Duktape doesn't call this macro for every internal native call. The macro -+ is called in code paths that are involved in potentially unlimited -+ recursion (such as making Ecmascript/native function calls, invoking -+ getters and Proxy traps, and resolving Proxy chains) and code paths -+ requiring a lot of stack space temporarily. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER.yaml -new file mode 100644 -index 0000000..9719a45 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER -+introduced: 1.0.0 -+removed: 2.3.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ In ES5.1 trailing gaps of an argument array don't count towards the result -+ length. This is in essence a specification "bug" which was fixed in ES2015. -+ This option was removed in 2.3.0, and the remaining behavior matches ES2015. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_MAP_TRAILER.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_MAP_TRAILER.yaml -new file mode 100644 -index 0000000..9e46964 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_MAP_TRAILER.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_NONSTD_ARRAY_MAP_TRAILER -+introduced: 1.0.0 -+removed: 2.3.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ This option was removed in 2.3.0 as it was unnecessary and in essence fixing -+ a Duktape bug. ES5.0/ES5.1 already behave like ES2015 in that trailing gaps -+ in the input don't affect the result length. The result array is created -+ with a length based on the input array in Step 6 of ES5.1 Section 15.4.4.19 -+ and subsequent index writes don't affect the length. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml -new file mode 100644 -index 0000000..c75a785 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ For better compatibility with existing code, enable non-standard -+ Array.prototype.splice() behavior when the second argument (deleteCount) -+ is not given: the splice operation is extended to the end of the array, see -+ https://github.com/svaarala/duktape/blob/master/tests/ecmascript/test-bi-array-proto-splice-no-delcount.js. -+ -+ If this option is disabled, splice() will behave in a strictly conforming -+ fashion, treating a missing deleteCount the same as an undefined (or 0) -+ value. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.yaml -new file mode 100644 -index 0000000..86f4d67 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_CALLER_PROPERTY.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -+introduced: 1.0.0 -+default: false -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Add a non-standard "caller" property to non-strict function instances -+ for better compatibility with existing code. The semantics of this -+ property are not standardized and may vary between engines; Duktape tries -+ to behave close to V8 and Spidermonkey. See -+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller -+ description of the property. This feature disables tail call support. -+ -+ This feature conflicts with several other features, so you should use it -+ only if it's absolutely necessary. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY.yaml -new file mode 100644 -index 0000000..88ed487 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY -+introduced: 1.0.0 -+default: false -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Add a non-standard "source" property to function instances. This allows -+ function toString() to print out the actual function source. The property -+ is disabled by default because it increases memory footprint. -+ -+ NOTE: Unimplemented as of Duktape 1.3.0. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_STMT.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_STMT.yaml -new file mode 100644 -index 0000000..be0ba88 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_FUNC_STMT.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_NONSTD_FUNC_STMT -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Enable support for function declarations outside program or function top -+ level (also known as "function statements"). Such declarations are -+ non-standard and the strictly compliant behavior is to treat them as a -+ SyntaxError. When this option is enabled (recommended), Duktape behavior -+ is to treat them like ordinary function declarations ("hoist" them to -+ function top) with V8-like semantics. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_GETTER_KEY_ARGUMENT.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_GETTER_KEY_ARGUMENT.yaml -new file mode 100644 -index 0000000..7ffd48a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_GETTER_KEY_ARGUMENT.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_NONSTD_GETTER_KEY_ARGUMENT -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Give getter calls the accessed property name as an additional non-standard -+ argument. This allows a single getter function to be reused for multiple -+ properties more easily. See -+ http://duktape.org/guide.html#propertyvirtualization. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_JSON_ESC_U2028_U2029.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_JSON_ESC_U2028_U2029.yaml -new file mode 100644 -index 0000000..d82c012 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_JSON_ESC_U2028_U2029.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_NONSTD_JSON_ESC_U2028_U2029 -+introduced: 1.1.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ When enabled, Duktape JSON.stringify() will escape U+2028 and U+2029 which -+ is non-compliant behavior. This is recommended to make JSON.stringify() -+ output valid when embedded in a web page or parsed with eval(). -+ -+ When disabled, Duktape provides the compliant behavior, i.e. no escaping -+ for U+2028 and U+2029. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE.yaml -new file mode 100644 -index 0000000..edfa774 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Replaced by DUK_USE_ES6_REGEXP_SYNTAX. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.yaml -new file mode 100644 -index 0000000..b517b03 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_SETTER_KEY_ARGUMENT.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_NONSTD_SETTER_KEY_ARGUMENT -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Give setter calls the accessed property name as an additional non-standard -+ argument. This allows a single setter function to be reused for multiple -+ properties more easily. See -+ http://duktape.org/guide.html#propertyvirtualization. -diff --git a/dist/source/config/config-options/DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT.yaml b/dist/source/config/config-options/DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT.yaml -new file mode 100644 -index 0000000..44d0ee3 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT -+introduced: 1.2.0 -+default: true -+tags: -+ - ecmascript -+ - compliance -+description: > -+ Allow 32-bit codepoints in String.fromCharCode(). This is non-compliant -+ (the E5.1 specification has a ToUint16() coercion for the codepoints) but -+ useful because Duktape supports non-BMP strings. -+ -+ When disabled, Duktape provides the compliant behavior. -diff --git a/dist/source/config/config-options/DUK_USE_NO_DOUBLE_ALIASING_SELFTEST.yaml b/dist/source/config/config-options/DUK_USE_NO_DOUBLE_ALIASING_SELFTEST.yaml -new file mode 100644 -index 0000000..6c9ff7e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NO_DOUBLE_ALIASING_SELFTEST.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_NO_DOUBLE_ALIASING_SELFTEST -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Disable double aliasing selftest (if self tests enabled). -+ -+ Double aliasing testcase fails when Emscripten-generated code is run. -+ This is not fatal because it only affects packed duk_tval which we -+ avoid with Emscripten. -diff --git a/dist/source/config/config-options/DUK_USE_NUMBER_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_NUMBER_BUILTIN.yaml -new file mode 100644 -index 0000000..c4b2d87 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_NUMBER_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_NUMBER_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide a Number built-in. -diff --git a/dist/source/config/config-options/DUK_USE_OBJECT_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_OBJECT_BUILTIN.yaml -new file mode 100644 -index 0000000..983dd9e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_OBJECT_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_OBJECT_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide an Object built-in. -diff --git a/dist/source/config/config-options/DUK_USE_OBJSIZES16.yaml b/dist/source/config/config-options/DUK_USE_OBJSIZES16.yaml -new file mode 100644 -index 0000000..a10cf1f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_OBJSIZES16.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_OBJSIZES16 -+introduced: 1.1.0 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit object entry and array part sizes (for low memory -+ environments). Also automatically drops support for an object hash part -+ to further reduce memory usage; there are rarely large objects in low -+ memory environments simply because there's no memory to store a lot of -+ properties. -diff --git a/dist/source/config/config-options/DUK_USE_OCTAL_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_OCTAL_SUPPORT.yaml -new file mode 100644 -index 0000000..0a0283e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_OCTAL_SUPPORT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_OCTAL_SUPPORT -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Enable optional octal number support (ECMAScript E5/E5.1 -+ Annex B: http://www.ecma-international.org/ecma-262/5.1/#sec-B). -+ Recommended because existing code bases use octal numbers. -diff --git a/dist/source/config/config-options/DUK_USE_OS_STRING.yaml b/dist/source/config/config-options/DUK_USE_OS_STRING.yaml -new file mode 100644 -index 0000000..b73aef0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_OS_STRING.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_OS_STRING -+introduced: 1.0.0 -+default: -+ string: "unknown" -+tags: -+ - portability -+description: > -+ Human-readable operating system string used in e.g. Duktape.env and debugger -+ protocol (example: linux). -diff --git a/dist/source/config/config-options/DUK_USE_PACKED_TVAL.yaml b/dist/source/config/config-options/DUK_USE_PACKED_TVAL.yaml -new file mode 100644 -index 0000000..1bda282 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PACKED_TVAL.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_PACKED_TVAL -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use a packed 8-byte representation for duk_tval. The packed representation -+ represents non-number values as special IEEE double NaN values, and is only -+ possible for platforms with 32-bit pointers. When the packed representation -+ is not available, Duktape uses a 12-16 byte struct/union which is more -+ portable. -diff --git a/dist/source/config/config-options/DUK_USE_PACKED_TVAL_POSSIBLE.yaml b/dist/source/config/config-options/DUK_USE_PACKED_TVAL_POSSIBLE.yaml -new file mode 100644 -index 0000000..8061032 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PACKED_TVAL_POSSIBLE.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_PACKED_TVAL_POSSIBLE -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Define when packed, 8-byte duk_tval representation is possible. -diff --git a/dist/source/config/config-options/DUK_USE_PACK_CLANG_ATTR.yaml b/dist/source/config/config-options/DUK_USE_PACK_CLANG_ATTR.yaml -new file mode 100644 -index 0000000..2e8e190 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PACK_CLANG_ATTR.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_PACK_CLANG_ATTR -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use clang-specific attribute to force struct packing. -diff --git a/dist/source/config/config-options/DUK_USE_PACK_DUMMY_MEMBER.yaml b/dist/source/config/config-options/DUK_USE_PACK_DUMMY_MEMBER.yaml -new file mode 100644 -index 0000000..5362cae ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PACK_DUMMY_MEMBER.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_PACK_DUMMY_MEMBER -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use dummy struct member to force struct packing. -diff --git a/dist/source/config/config-options/DUK_USE_PACK_GCC_ATTR.yaml b/dist/source/config/config-options/DUK_USE_PACK_GCC_ATTR.yaml -new file mode 100644 -index 0000000..3457640 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PACK_GCC_ATTR.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_PACK_GCC_ATTR -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use gcc-specific attribute to force struct packing. -diff --git a/dist/source/config/config-options/DUK_USE_PACK_MSVC_PRAGMA.yaml b/dist/source/config/config-options/DUK_USE_PACK_MSVC_PRAGMA.yaml -new file mode 100644 -index 0000000..b648307 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PACK_MSVC_PRAGMA.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_PACK_MSVC_PRAGMA -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Use msvc-specific attribute to force struct packing. -diff --git a/dist/source/config/config-options/DUK_USE_PANIC_ABORT.yaml b/dist/source/config/config-options/DUK_USE_PANIC_ABORT.yaml -new file mode 100644 -index 0000000..c62a4f4 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PANIC_ABORT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_PANIC_ABORT -+introduced: 1.0.0 -+removed: 2.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Call abort() when the default panic handler is invoked. -diff --git a/dist/source/config/config-options/DUK_USE_PANIC_EXIT.yaml b/dist/source/config/config-options/DUK_USE_PANIC_EXIT.yaml -new file mode 100644 -index 0000000..4909806 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PANIC_EXIT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_PANIC_EXIT -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Call exit() when the default panic handler is invoked. -diff --git a/dist/source/config/config-options/DUK_USE_PANIC_HANDLER.yaml b/dist/source/config/config-options/DUK_USE_PANIC_HANDLER.yaml -new file mode 100644 -index 0000000..a6ae86d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PANIC_HANDLER.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_PANIC_HANDLER -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Provide a custom panic handler. A custom panic handler is recommended for -+ any environment where recovery from fatal errors is important. A custom -+ handler can take appropriate action to recover, e.g. record the error and -+ reboot the target device. -diff --git a/dist/source/config/config-options/DUK_USE_PANIC_SEGFAULT.yaml b/dist/source/config/config-options/DUK_USE_PANIC_SEGFAULT.yaml -new file mode 100644 -index 0000000..4792125 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PANIC_SEGFAULT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_PANIC_SEGFAULT -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Cause an intentional segfault when the default panic handler is invoked. -+ This is useful when debugging with valgrind because a segfault provides -+ a nice C traceback in valgrind. -diff --git a/dist/source/config/config-options/DUK_USE_PARANOID_DATE_COMPUTATION.yaml b/dist/source/config/config-options/DUK_USE_PARANOID_DATE_COMPUTATION.yaml -new file mode 100644 -index 0000000..02a7280 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PARANOID_DATE_COMPUTATION.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_PARANOID_DATE_COMPUTATION -+introduced: 1.0.0 -+default: false # XXX: make default detect C99/C++11? -+tags: -+ - portability -+description: > -+ There was a curious bug where test-bi-date-canceling.js would fail e.g. -+ on 64-bit Ubuntu, gcc-4.8.1, -m32, and no -std=c99. Some date computations -+ using doubles would be optimized which then broke some corner case tests. -+ The problem goes away by adding 'volatile' to the datetime computations. -+ Not sure what the actual triggering conditions are, but using this on -+ non-C99 systems solves the known issues and has relatively little cost -+ on other platforms. -+ -+ Recommended for non-C99 platforms. -diff --git a/dist/source/config/config-options/DUK_USE_PARANOID_ERRORS.yaml b/dist/source/config/config-options/DUK_USE_PARANOID_ERRORS.yaml -new file mode 100644 -index 0000000..66c613b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PARANOID_ERRORS.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_PARANOID_ERRORS -+introduced: 1.4.0 -+default: false -+tags: -+ - ecmascript -+ - sandbox -+description: > -+ When enabled, error messages won't involve summarization of keys or values. -+ Summaries may be an issue in some security sensitive environments because -+ error messages will include e.g. property keys. -+ -+ The default is to summarize offending base value and key for property access -+ errors such as "null.foo = 123;", invalid calls such as "undefined()", etc. -+ Base values and keys are summarized using duk_push_string_tval_readable(). -diff --git a/dist/source/config/config-options/DUK_USE_PARANOID_MATH.yaml b/dist/source/config/config-options/DUK_USE_PARANOID_MATH.yaml -new file mode 100644 -index 0000000..e150a40 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PARANOID_MATH.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_PARANOID_MATH -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Rely as little as possible on compiler behavior for NaN comparison, -+ signed zero handling, etc. May be needed for (very) broken compilers. -diff --git a/dist/source/config/config-options/DUK_USE_PC2LINE.yaml b/dist/source/config/config-options/DUK_USE_PC2LINE.yaml -new file mode 100644 -index 0000000..c31b757 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PC2LINE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_PC2LINE -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Record a "pc2line" map into function instances which allows bytecode program -+ counter values to be mapped into line numbers e.g. in error tracebacks. -+ -+ Without this map, exceptions won't have meaningful line numbers but function -+ instances will have a smaller footprint. -diff --git a/dist/source/config/config-options/DUK_USE_PERFORMANCE_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_PERFORMANCE_BUILTIN.yaml -new file mode 100644 -index 0000000..0b47be6 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PERFORMANCE_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_PERFORMANCE_BUILTIN -+introduced: 2.2.0 -+default: true -+tags: -+ - performance-api -+description: > -+ Provide a 'performance' global object based on https://www.w3.org/TR/hr-time/. -diff --git a/dist/source/config/config-options/DUK_USE_POW_NETBSD_WORKAROUND.yaml b/dist/source/config/config-options/DUK_USE_POW_NETBSD_WORKAROUND.yaml -new file mode 100644 -index 0000000..09803a7 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_POW_NETBSD_WORKAROUND.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_POW_NETBSD_WORKAROUND -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - portability -+description: > -+ NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, -+ see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround. -+ -+ (This might be a wider problem; if so, generalize the define name.) -diff --git a/dist/source/config/config-options/DUK_USE_POW_WORKAROUNDS.yaml b/dist/source/config/config-options/DUK_USE_POW_WORKAROUNDS.yaml -new file mode 100644 -index 0000000..91a2113 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_POW_WORKAROUNDS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_POW_WORKAROUNDS -+introduced: 2.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Enable workarounds to common pow() semantics issues. At least NetBSD -+ 6.0 x86 and Cygwin/MinGW have such issues, see test-bug-netbsd-math-pow.js -+ and test-bug-mingw-math-issues.js. -diff --git a/dist/source/config/config-options/DUK_USE_PREFER_SIZE.yaml b/dist/source/config/config-options/DUK_USE_PREFER_SIZE.yaml -new file mode 100644 -index 0000000..8113ff2 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PREFER_SIZE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_PREFER_SIZE -+introduced: 1.2.0 -+default: false -+tags: -+ - lowmemory -+description: > -+ Catch-all flag which can be used to choose between variant algorithms -+ where a speed-size tradeoff exists (e.g. lookup tables). When it really -+ matters, specific use flags may be appropriate. -diff --git a/dist/source/config/config-options/DUK_USE_PROMISE_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_PROMISE_BUILTIN.yaml -new file mode 100644 -index 0000000..8eb4b38 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PROMISE_BUILTIN.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_PROMISE_BUILTIN -+introduced: 2.2.0 -+default: false # disabled until fully functional -+tags: -+ - ecmascript -+description: > -+ Enable Promise built-in. -+ -+ At present entirely non-functional, and disabled by default. -diff --git a/dist/source/config/config-options/DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS.yaml b/dist/source/config/config-options/DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS.yaml -new file mode 100644 -index 0000000..3afcbec ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS -+introduced: 1.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Provide default allocation functions. -+ -+ At the moment this option should be enabled. -diff --git a/dist/source/config/config-options/DUK_USE_RDTSC.yaml b/dist/source/config/config-options/DUK_USE_RDTSC.yaml -new file mode 100644 -index 0000000..04b65b1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_RDTSC.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_RDTSC -+introduced: 1.3.0 -+removed: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Macro to provide an x86/x64 RDTSC timestamp for debug prints. -diff --git a/dist/source/config/config-options/DUK_USE_REFCOUNT16.yaml b/dist/source/config/config-options/DUK_USE_REFCOUNT16.yaml -new file mode 100644 -index 0000000..93d7387 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REFCOUNT16.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_REFCOUNT16 -+introduced: 1.1.0 -+default: false -+tags: -+ - lowmemory -+ - experimental -+ - gc -+description: > -+ Use a 16-bit reference count field (for low memory environments). -diff --git a/dist/source/config/config-options/DUK_USE_REFCOUNT32.yaml b/dist/source/config/config-options/DUK_USE_REFCOUNT32.yaml -new file mode 100644 -index 0000000..363411f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REFCOUNT32.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_REFCOUNT32 -+introduced: 2.1.0 -+default: true -+tags: -+ - gc -+description: > -+ Use a 32-bit reference count field. -+ -+ While on some 64-bit systems it's theoretically possible to wrap a 32-bit -+ counter field, assuming a 16-byte duk_tval the Duktape heap would have to -+ be larger than 64GB for that to happen. Because of this the default is to -+ use a 32-bit refcount field. -diff --git a/dist/source/config/config-options/DUK_USE_REFERENCE_COUNTING.yaml b/dist/source/config/config-options/DUK_USE_REFERENCE_COUNTING.yaml -new file mode 100644 -index 0000000..a59bad2 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REFERENCE_COUNTING.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_REFERENCE_COUNTING -+introduced: 1.0.0 -+default: true -+tags: -+ - gc -+description: > -+ Use reference counting for garbage collection. -diff --git a/dist/source/config/config-options/DUK_USE_REFLECT_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_REFLECT_BUILTIN.yaml -new file mode 100644 -index 0000000..bedd9c1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REFLECT_BUILTIN.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_REFLECT_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Provide a Reflect built-in. The ES6 Reflect object provides a collection of -+ methods for examining and manipulating objects at runtime. -diff --git a/dist/source/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml b/dist/source/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml -new file mode 100644 -index 0000000..de83dae ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REFZERO_FINALIZER_TORTURE.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_REFZERO_FINALIZER_TORTURE -+introduced: 1.3.0 -+removed: 2.1.0 -+related: -+ - DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE -+default: false -+tags: -+ - gc -+ - memory -+ - development -+ - torture -+description: > -+ Development time option: simulate a fake finalizer call for every object -+ going through refzero freeing. This is useful to detect bugs caused by -+ finalizer side effects in e.g. call handling. -diff --git a/dist/source/config/config-options/DUK_USE_REGEXP_CANON_BITMAP.yaml b/dist/source/config/config-options/DUK_USE_REGEXP_CANON_BITMAP.yaml -new file mode 100644 -index 0000000..36ca02f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REGEXP_CANON_BITMAP.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_REGEXP_CANON_BITMAP -+introduced: 2.2.0 -+default: true -+tags: -+ - performance -+ - unicode -+description: > -+ Use a small lookup table (footprint impact is ~300-400 bytes) to speed up -+ case insensitive RegExp canonicalization. The result is still much slower -+ than with DUK_USE_REGEXP_CANON_WORKAROUND but ~50x faster than without the -+ lookup. -diff --git a/dist/source/config/config-options/DUK_USE_REGEXP_CANON_WORKAROUND.yaml b/dist/source/config/config-options/DUK_USE_REGEXP_CANON_WORKAROUND.yaml -new file mode 100644 -index 0000000..f363840 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REGEXP_CANON_WORKAROUND.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_REGEXP_CANON_WORKAROUND -+introduced: 1.4.0 -+default: false -+tags: -+ - performance -+ - unicode -+ - experimental -+description: > -+ Use a 128kB lookup table for RegExp codepoint canonicalization to improve -+ performance of case insensitive RegExp handling. -+ -+ This is a temporary workaround until there's better support for faster -+ Unicode handling. -diff --git a/dist/source/config/config-options/DUK_USE_REGEXP_COMPILER_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_REGEXP_COMPILER_RECLIMIT.yaml -new file mode 100644 -index 0000000..ea653d7 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REGEXP_COMPILER_RECLIMIT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_REGEXP_COMPILER_RECLIMIT -+introduced: 1.3.0 -+default: 10000 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ RegExp compiler native call stack recursion limit. -diff --git a/dist/source/config/config-options/DUK_USE_REGEXP_EXECUTOR_RECLIMIT.yaml b/dist/source/config/config-options/DUK_USE_REGEXP_EXECUTOR_RECLIMIT.yaml -new file mode 100644 -index 0000000..cc1dfca ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REGEXP_EXECUTOR_RECLIMIT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_REGEXP_EXECUTOR_RECLIMIT -+introduced: 1.3.0 -+default: 10000 -+tags: -+ - portability -+ - cstackdepth -+description: > -+ RegExp executor native call stack recursion limit. -diff --git a/dist/source/config/config-options/DUK_USE_REGEXP_SUPPORT.yaml b/dist/source/config/config-options/DUK_USE_REGEXP_SUPPORT.yaml -new file mode 100644 -index 0000000..39ed04e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REGEXP_SUPPORT.yaml -@@ -0,0 +1,15 @@ -+define: DUK_USE_REGEXP_SUPPORT -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+ - lowmemory -+description: > -+ Enable support for regular expressions (recommended). -+ -+ When disabled, regexp literals are treated as a SyntaxError, RegExp -+ constructor and prototype functions throw an error, -+ String.prototype.replace() throws an error if given a regexp search value, -+ String.prototype.split() throws an error if given a regexp separator value, -+ String.prototype.search() and String.prototype.match() throw an error -+ unconditionally. -diff --git a/dist/source/config/config-options/DUK_USE_REPL_FPCLASSIFY.yaml b/dist/source/config/config-options/DUK_USE_REPL_FPCLASSIFY.yaml -new file mode 100644 -index 0000000..8a13af1 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REPL_FPCLASSIFY.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_REPL_FPCLASSIFY -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Provide a built-in replacement for fpclassify(), duk_repl_fpclassify. -+ -+ When enabled, define DUK_FPCLASSIFY as duk_repl_fpclassify. -+ -+# XXX: the dependency between DUK_USE_REPL_FPCLASSIFY and DUK_FPCLASSIFY -+# is a bit awkward. -diff --git a/dist/source/config/config-options/DUK_USE_REPL_ISFINITE.yaml b/dist/source/config/config-options/DUK_USE_REPL_ISFINITE.yaml -new file mode 100644 -index 0000000..6d66d57 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REPL_ISFINITE.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_REPL_ISFINITE -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Provide a built-in replacement for isfinite(), duk_repl_isfinite. -+ -+ When enabled, define DUK_ISFINITE as duk_repl_isfinite. -+ -+# XXX: the dependency between DUK_USE_REPL_ISFINITE and DUK_ISFINITE -+# is a bit awkward. -diff --git a/dist/source/config/config-options/DUK_USE_REPL_ISINF.yaml b/dist/source/config/config-options/DUK_USE_REPL_ISINF.yaml -new file mode 100644 -index 0000000..19afbca ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REPL_ISINF.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_REPL_ISINF -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Provide a built-in replacement for isinf(), duk_repl_isinf. -+ -+ When enabled, define DUK_ISINF as duk_repl_isinf. -+ -+# XXX: the dependency between DUK_USE_REPL_ISINF and DUK_ISINF -+# is a bit awkward. -diff --git a/dist/source/config/config-options/DUK_USE_REPL_ISNAN.yaml b/dist/source/config/config-options/DUK_USE_REPL_ISNAN.yaml -new file mode 100644 -index 0000000..9e9558e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REPL_ISNAN.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_REPL_ISNAN -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Provide a built-in replacement for isnan(), duk_repl_isnan. -+ -+ When enabled, define DUK_ISNAN as duk_repl_isnan. -+ -+# XXX: the dependency between DUK_USE_REPL_ISNAN and DUK_ISNAN -+# is a bit awkward. -diff --git a/dist/source/config/config-options/DUK_USE_REPL_SIGNBIT.yaml b/dist/source/config/config-options/DUK_USE_REPL_SIGNBIT.yaml -new file mode 100644 -index 0000000..92a87dd ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_REPL_SIGNBIT.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_REPL_SIGNBIT -+introduced: 1.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Provide a built-in replacement for signbit(), duk_repl_signbit. -+ -+ When enabled, define DUK_SIGNBIT as duk_repl_signbit. -+ -+# XXX: the dependency between DUK_USE_REPL_SIGNBIT and DUK_SIGNBIT -+# is a bit awkward. -diff --git a/dist/source/config/config-options/DUK_USE_ROM_GLOBAL_CLONE.yaml b/dist/source/config/config-options/DUK_USE_ROM_GLOBAL_CLONE.yaml -new file mode 100644 -index 0000000..70cdb5f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ROM_GLOBAL_CLONE.yaml -@@ -0,0 +1,18 @@ -+define: DUK_USE_ROM_GLOBAL_CLONE -+introduced: 1.5.0 -+requires: -+ - DUK_USE_ROM_STRINGS -+ - DUK_USE_ROM_OBJECTS -+conflicts: -+ - DUK_USE_ROM_GLOBAL_INHERIT -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ When using ROM built-in objects, create a RAM-based global object by copying -+ the properties of the ROM-based global object into a fresh empty object. -+ -+ Having a writable global object is usually expected; if the global object is -+ not writable, it's not possible to e.g. declare functions outside of CommonJS -+ modules. -diff --git a/dist/source/config/config-options/DUK_USE_ROM_GLOBAL_INHERIT.yaml b/dist/source/config/config-options/DUK_USE_ROM_GLOBAL_INHERIT.yaml -new file mode 100644 -index 0000000..fbfec9a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ROM_GLOBAL_INHERIT.yaml -@@ -0,0 +1,23 @@ -+define: DUK_USE_ROM_GLOBAL_INHERIT -+introduced: 1.5.0 -+requires: -+ - DUK_USE_ROM_STRINGS -+ - DUK_USE_ROM_OBJECTS -+conflicts: -+ - DUK_USE_ROM_GLOBAL_CLONE -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ When using ROM built-in objects, create a RAM-based global object by creating -+ a fresh empty object which inherits from the ROM-based global object. This -+ provides all the standard bindings with a small RAM footprint cost, but still -+ allows the global object to be extended and existing bindings overwritten -+ (but not deleted). The downside of this compared to cloning a global object -+ is that the inheritance is not fully transparent and the result is less -+ compliant. -+ -+ Having a writable global object is usually expected; if the global object is -+ not writable, it's not possible to e.g. declare functions outside of CommonJS -+ modules. -diff --git a/dist/source/config/config-options/DUK_USE_ROM_OBJECTS.yaml b/dist/source/config/config-options/DUK_USE_ROM_OBJECTS.yaml -new file mode 100644 -index 0000000..905319c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ROM_OBJECTS.yaml -@@ -0,0 +1,22 @@ -+define: DUK_USE_ROM_OBJECTS -+introduced: 1.5.0 -+requires: -+ - DUK_USE_ROM_STRINGS # use both DUK_USE_ROM_STRINGS + DUK_USE_ROM_OBJECTS together for now -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable support for built-in objects compiled as constants and placed in a -+ read-only data section. This reduces startup RAM usage considerably at the -+ cost of a larger code footprint and slower performance overall. The built-in -+ objects will be immutable: the objects will be non-extensible. -+ -+ ROM objects will always be non-extensible and properties are forced to be -+ non-configurable. Other property attributes will have their usual values; -+ in particular, properties can be "writable" from a property attributes -+ standpoint, but an attempt to actually change the property value will fail -+ with a TypeError. This may seem strange, but is necessary to allow a -+ property value to be overridden in a RAM object inheriting from a ROM object: -+ if the inherited ROM property was not writable, ECMAScript semantics would -+ prevent a new property from being established in the RAM object. -diff --git a/dist/source/config/config-options/DUK_USE_ROM_PTRCOMP_FIRST.yaml b/dist/source/config/config-options/DUK_USE_ROM_PTRCOMP_FIRST.yaml -new file mode 100644 -index 0000000..50fa63c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ROM_PTRCOMP_FIRST.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_ROM_PTRCOMP_FIRST -+introduced: 1.5.0 -+related: -+ - DUK_USE_ROM_STRINGS -+ - DUK_USE_ROM_OBJECTS -+default: 0xf800 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ When using ROM pointer compression ROM pointers are compressed to the -+ integer range [DUK_USE_ROM_PTRCOMP_FIRST,0xffff]. The default value -+ allows for 2048 ROM pointers, which can point to objects and strings. -+ -+ You may need to lower this value to support more pointers if there are -+ a lot of custom ROM strings/objects. -diff --git a/dist/source/config/config-options/DUK_USE_ROM_STRINGS.yaml b/dist/source/config/config-options/DUK_USE_ROM_STRINGS.yaml -new file mode 100644 -index 0000000..bdb8871 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ROM_STRINGS.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_ROM_STRINGS -+introduced: 1.5.0 -+requires: -+ - DUK_USE_ROM_OBJECTS # use both DUK_USE_ROM_STRINGS + DUK_USE_ROM_OBJECTS together for now -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable support for built-in (and optional user-supplied strings) which are -+ compiled as constants and placed in a read-only data section. This reduces -+ startup RAM usage considerably at the cost of a larger code footprint and -+ slower string interning. -diff --git a/dist/source/config/config-options/DUK_USE_SECTION_B.yaml b/dist/source/config/config-options/DUK_USE_SECTION_B.yaml -new file mode 100644 -index 0000000..f6265b6 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SECTION_B.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_SECTION_B -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Enable optional features in ECMAScript specification -+ Annex B: http://www.ecma-international.org/ecma-262/5.1/#sec-B. -+ -+ When disabled, escape(), unescape(), and String.prototype.substr() -+ throw an error. -diff --git a/dist/source/config/config-options/DUK_USE_SELF_TESTS.yaml b/dist/source/config/config-options/DUK_USE_SELF_TESTS.yaml -new file mode 100644 -index 0000000..8c9b77c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SELF_TESTS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_SELF_TESTS -+introduced: 1.0.0 -+default: false -+tags: -+ - debug -+description: > -+ Perform run-time self tests when a Duktape heap is created. Catches -+ platform/compiler problems which cannot be reliably detected during -+ compile time. Not enabled by default because of the extra footprint. -diff --git a/dist/source/config/config-options/DUK_USE_SETJMP.yaml b/dist/source/config/config-options/DUK_USE_SETJMP.yaml -new file mode 100644 -index 0000000..9b18afe ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SETJMP.yaml -@@ -0,0 +1,17 @@ -+define: DUK_USE_SETJMP -+introduced: 1.1.0 -+removed: 1.5.0 -+default: true -+tags: -+ - portability -+description: > -+ Use setjmp/longjmp for long control transfers. This is the most portable -+ option for long control transfers. -+ -+ The downside of setjmp/longjmp is that signal mask saving behavior is not -+ specified and varies between platforms. Signal mask saving may have a -+ significant performance impact so you may want to force a specific provider -+ if performance matters for your application. (This is the case for macOS, -+ for instance.) -+ -+ Removed in Duktape 1.5.0: edit duk_config.h directly. -diff --git a/dist/source/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml b/dist/source/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml -new file mode 100644 -index 0000000..221b0d6 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SHEBANG_COMMENTS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_SHEBANG_COMMENTS -+introduced: 2.1.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Support parsing of a "shebang" comment ('#!...') on the first line of -+ source text. -diff --git a/dist/source/config/config-options/DUK_USE_SHUFFLE_TORTURE.yaml b/dist/source/config/config-options/DUK_USE_SHUFFLE_TORTURE.yaml -new file mode 100644 -index 0000000..822ca6e ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SHUFFLE_TORTURE.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_SHUFFLE_TORTURE -+introduced: 1.2.0 -+default: false -+tags: -+ - gc -+ - memory -+ - development -+ - torture -+description: > -+ Development time option: force compiler to shuffle every possible opcode -+ to stress shuffle behavior which is otherwise difficult to test for -+ comprehensively. -diff --git a/dist/source/config/config-options/DUK_USE_SIGSETJMP.yaml b/dist/source/config/config-options/DUK_USE_SIGSETJMP.yaml -new file mode 100644 -index 0000000..7a9a383 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SIGSETJMP.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_SIGSETJMP -+introduced: 1.1.0 -+removed: 1.5.0 -+default: false -+tags: -+ - portability -+description: > -+ Use sigsetjmp/siglongjmp with savesigs == 0 for long control -+ transfers (i.e. signal mask not saved/restored). See comments in -+ DUK_USE_SETJMP. -+ -+ Removed in Duktape 1.5.0: edit duk_config.h directly. -diff --git a/dist/source/config/config-options/DUK_USE_SOURCE_NONBMP.yaml b/dist/source/config/config-options/DUK_USE_SOURCE_NONBMP.yaml -new file mode 100644 -index 0000000..9682a17 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SOURCE_NONBMP.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_SOURCE_NONBMP -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+ - lowmemory -+description: > -+ Enable accurate Unicode support for non-BMP characters in source code. -+ -+ When disabled non-BMP characters are always accepted as identifier -+ characters. Disabling this option saves a little bit of code footprint. -diff --git a/dist/source/config/config-options/DUK_USE_STRHASH16.yaml b/dist/source/config/config-options/DUK_USE_STRHASH16.yaml -new file mode 100644 -index 0000000..f66e36b ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRHASH16.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_STRHASH16 -+introduced: 1.1.0 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit string hash field (for low memory environments). -diff --git a/dist/source/config/config-options/DUK_USE_STRHASH_DENSE.yaml b/dist/source/config/config-options/DUK_USE_STRHASH_DENSE.yaml -new file mode 100644 -index 0000000..af1b28f ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRHASH_DENSE.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_STRHASH_DENSE -+introduced: 1.4.0 -+default: false -+tags: -+ - performance -+ - sandbox -+description: > -+ Use the slower but more dense string hash algorithm from Duktape 1.3.0 and -+ prior (based on Murmurhash2). This may be useful if you're experiencing -+ collision issues with the default hash algorithm. -diff --git a/dist/source/config/config-options/DUK_USE_STRHASH_SKIP_SHIFT.yaml b/dist/source/config/config-options/DUK_USE_STRHASH_SKIP_SHIFT.yaml -new file mode 100644 -index 0000000..d9a4d04 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRHASH_SKIP_SHIFT.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_STRHASH_SKIP_SHIFT -+introduced: 1.4.0 -+default: 5 -+tags: -+ - performance -+description: > -+ Shift value to use for string hash skip offset when using the default -+ (fast) string hash. The skip offset is calculated as: -+ ((length >> DUK_USE_STRHASH_SKIP_SHIFT) + 1). A higher value will be -+ slower but sample the string more densely. -+ -+ You should only change this if you run into issues with the default value. -diff --git a/dist/source/config/config-options/DUK_USE_STRICT_DECL.yaml b/dist/source/config/config-options/DUK_USE_STRICT_DECL.yaml -new file mode 100644 -index 0000000..8e6ff32 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRICT_DECL.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_STRICT_DECL -+introduced: 1.1.0 -+default: true -+tags: -+ - ecmascript -+ - experimental -+description: > -+ Enable support for "use strict" declaration (recommended). -+ -+ When disabled, ECMAScript code is always executed in non-strict mode. -+ Duktape/C functions remain strict. This option is useful in some legacy -+ environments where "use strict" declarations are used in existing code -+ base but the Javascript engine didn't actually support strict mode. -diff --git a/dist/source/config/config-options/DUK_USE_STRICT_UTF8_SOURCE.yaml b/dist/source/config/config-options/DUK_USE_STRICT_UTF8_SOURCE.yaml -new file mode 100644 -index 0000000..ceac807 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRICT_UTF8_SOURCE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_STRICT_UTF8_SOURCE -+introduced: 1.0.0 -+default: false -+tags: -+ - ecmascript -+description: > -+ Enable strict UTF-8 parsing of source code. -+ -+ When disabled, non-shortest encodings (normally invalid UTF-8) and surrogate -+ pair codepoints are accepted as valid source code characters. Disabling -+ this option breaks compatibility with some test262 tests. -diff --git a/dist/source/config/config-options/DUK_USE_STRING_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_STRING_BUILTIN.yaml -new file mode 100644 -index 0000000..c9d11ed ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRING_BUILTIN.yaml -@@ -0,0 +1,7 @@ -+define: DUK_USE_STRING_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide a String built-in. -diff --git a/dist/source/config/config-options/DUK_USE_STRLEN16.yaml b/dist/source/config/config-options/DUK_USE_STRLEN16.yaml -new file mode 100644 -index 0000000..4d8a801 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRLEN16.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_STRLEN16 -+introduced: 1.1.0 -+default: false -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit string length field (for low memory environments). -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_CHAIN.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_CHAIN.yaml -new file mode 100644 -index 0000000..67c3205 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_CHAIN.yaml -@@ -0,0 +1,27 @@ -+define: DUK_USE_STRTAB_CHAIN -+introduced: 1.1.0 -+removed: 2.1.0 -+related: -+ - DUK_USE_STRTAB_CHAIN_SIZE -+default: false -+tags: -+ - lowmemory -+description: > -+ Replace the default (open addressing, probing) string table structure with -+ one based on separate chaining. There is a fixed-size top level hash table -+ (whose size is defined using DUK_USE_STRTAB_CHAIN_SIZE), with each entry in -+ the hash table being: (a) NULL, (b) a duk_hstring pointer, or (c) a pointer -+ to an array of duk_hstring pointers. The pointer arrays are gappy (the gaps -+ are reused on new inserts) and are never shrunk at the moment. -+ -+ This option is intended for low memory environments to make Duktape's memory -+ behavior match a typical pool-based allocator better as follows: -+ -+ The top level fixed structure never changes size, so there is no hash table -+ resize, and thus no need for resize temporaries. The default string table -+ algorithm needs resizing from time to time and doesn't resize in place, so -+ you effectively need twice the string table size temporarily during a resize. -+ -+ The pointer arrays vary in size, but their size (typically 8 to 64 bytes, -+ depending on the load factor) matches that of many other allocations which -+ works well with a pooled allocator. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml -new file mode 100644 -index 0000000..a1e4f08 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_CHAIN_SIZE.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_STRTAB_CHAIN_SIZE -+introduced: 1.1.0 -+removed: 2.1.0 -+requires: -+ - DUK_USE_STRTAB_CHAIN -+default: false -+tags: -+ - lowmemory -+description: > -+ Define stringtable size for DUK_USE_STRTAB_CHAIN. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml -new file mode 100644 -index 0000000..111a1a8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_GROW_LIMIT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_STRTAB_GROW_LIMIT -+introduced: 2.1.0 -+default: 17 # 17/16 = 1.0625 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Grow top level strtable allocation when load factor reaches this value. -+ Expressed as a .4 fixed point; the load factor is computed as -+ floor((count / size) * 16.0), e.g. 32 means a load factor of 2.0. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml -new file mode 100644 -index 0000000..da7feef ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_MAXSIZE.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_STRTAB_MAXSIZE -+introduced: 2.1.0 -+default: 268435456 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Maximum size for Duktape heap string table, must be 2^N, and small enough -+ so that if the value is multiplied by sizeof(duk_hstring *) it won't overflow -+ duk_size_t. -+ -+ To avoid resizing the strtable at all, set DUK_USE_STRTAB_MINSIZE and -+ DUK_USE_STRTAB_MAXSIZE to the same value. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml -new file mode 100644 -index 0000000..55ba319 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_MINSIZE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_STRTAB_MINSIZE -+introduced: 2.1.0 -+default: 1024 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Minimum size for Duktape heap string table, must be 2^N, and should never -+ be lower than 64. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_PROBE.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_PROBE.yaml -new file mode 100644 -index 0000000..c65ac17 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_PROBE.yaml -@@ -0,0 +1,8 @@ -+define: DUK_USE_STRTAB_PROBE -+introduced: 1.1.0 -+removed: 2.1.0 -+default: true -+tags: -+ - lowmemory -+description: > -+ Use the default open addressing (probing) based string table algorithm. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml -new file mode 100644 -index 0000000..7b93bff ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_PTRCOMP.yaml -@@ -0,0 +1,14 @@ -+define: DUK_USE_STRTAB_PTRCOMP -+introduced: 2.1.0 -+default: false -+requires: -+ - DUK_USE_HEAPPTR16 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Pointer compress the top level heap->strtable[] string table. On 32-bit -+ targets this saves 2 bytes per entry, e.g. for 256 entries 0.5kB. However, -+ the additional pointer compression code increases footprint by 200-300 -+ bytes. The option also reduces performance a little bit, so this should -+ be enabled when RAM is much more constrained than ROM. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml -new file mode 100644 -index 0000000..383a434 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_RESIZE_CHECK_MASK.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_STRTAB_RESIZE_CHECK_MASK -+introduced: 2.1.0 -+default: 255 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Somewhat technical: bit mask (must be 2^N-1) used against heap->st_count to -+ determine the interval between string table resize checks. A resize check -+ is made when heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK is zero. -+ -+ A large value makes string table grow/shrink checks less frequent. Usually -+ this has very little practical impact on memory performance. There are -+ corner cases, such as dereferencing a large number of strings simultaneously, -+ where this parameter affects how many new strings need to be inserted before -+ the string table shrinks to a more appropriate size. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml -new file mode 100644 -index 0000000..372d916 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_SHRINK_LIMIT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_STRTAB_SHRINK_LIMIT -+introduced: 2.1.0 -+default: 6 # 6/16 = 0.375 -+tags: -+ - performance -+ - lowmemory -+description: > -+ Shrink top level strtable allocation when load factor reaches this value. -+ Expressed as a .4 fixed point; the load factor is computed as -+ floor((count / size) * 16.0), e.g. 8 means a load factor of 0.5. -diff --git a/dist/source/config/config-options/DUK_USE_STRTAB_TORTURE.yaml b/dist/source/config/config-options/DUK_USE_STRTAB_TORTURE.yaml -new file mode 100644 -index 0000000..86186e8 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_STRTAB_TORTURE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_STRTAB_TORTURE -+introduced: 2.1.0 -+default: false -+tags: -+ - torture -+description: > -+ Resize string table (grow, shrink back) for every intern. Ensures string -+ table chaining is correct, and resize side effects are exercised on every -+ resize. -diff --git a/dist/source/config/config-options/DUK_USE_SYMBOL_BUILTIN.yaml b/dist/source/config/config-options/DUK_USE_SYMBOL_BUILTIN.yaml -new file mode 100644 -index 0000000..08a71aa ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_SYMBOL_BUILTIN.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_SYMBOL_BUILTIN -+introduced: 2.0.0 -+default: true -+tags: -+ - ecmascript2015 -+description: > -+ Provide ES6 Symbol built-ins. -+ -+ Even with the built-ins disabled, symbols created by C code are still -+ supported. -diff --git a/dist/source/config/config-options/DUK_USE_TAILCALL.yaml b/dist/source/config/config-options/DUK_USE_TAILCALL.yaml -new file mode 100644 -index 0000000..55fc5c2 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_TAILCALL.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_TAILCALL -+introduced: 1.0.0 -+conflicts: -+ - DUK_USE_NONSTD_FUNC_CALLER_PROPERTY -+default: true -+tags: -+ - ecmascript -+description: > -+ Enable tail call support (recommended). -+ -+ The non-standard function 'caller' property feature conflicts with -+ tailcalls quite severely so tailcalls must be disabled if the 'caller' -+ property is enabled. -diff --git a/dist/source/config/config-options/DUK_USE_TARGET_INFO.yaml b/dist/source/config/config-options/DUK_USE_TARGET_INFO.yaml -new file mode 100644 -index 0000000..6ea3305 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_TARGET_INFO.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_TARGET_INFO -+introduced: 1.2.0 -+default: -+ string: "unknown" -+tags: -+ - debugger -+description: > -+ Define a freeform human readable string to describe the target device (e.g. -+ "Arduino Yun"). This string will be sent as part of version/target info in -+ the debugger protocol and shows up in the debugger UI. -diff --git a/dist/source/config/config-options/DUK_USE_TRACEBACKS.yaml b/dist/source/config/config-options/DUK_USE_TRACEBACKS.yaml -new file mode 100644 -index 0000000..53403c0 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_TRACEBACKS.yaml -@@ -0,0 +1,12 @@ -+define: DUK_USE_TRACEBACKS -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Record traceback data into ECMAScript error objects. -+ -+ When disabled, traceback data is not recorded, but fileName/lineNumber of -+ the error cause are still recorded as explicit properties. Disabling this -+ option reduces footprint and makes error handling a bit faster, at the cost -+ of less informative ECMAScript errors. -diff --git a/dist/source/config/config-options/DUK_USE_TRACEBACK_DEPTH.yaml b/dist/source/config/config-options/DUK_USE_TRACEBACK_DEPTH.yaml -new file mode 100644 -index 0000000..6c8093d ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_TRACEBACK_DEPTH.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_TRACEBACK_DEPTH -+introduced: 1.0.0 -+default: 10 -+tags: -+ - ecmascript -+description: > -+ Define traceback collection depth. A large number causes tracedata to be -+ larger, taking more time to create and consuming more memory. A small -+ number makes tracebacks less useful. -+ -+ When tracebacks are disabled this option affects .fileName and .lineNumber -+ blaming. Error augmentation code won't look deeper than this value to find -+ a function to blame for error .fileName / .lineNumber. -diff --git a/dist/source/config/config-options/DUK_USE_UNALIGNED_ACCESSES_POSSIBLE.yaml b/dist/source/config/config-options/DUK_USE_UNALIGNED_ACCESSES_POSSIBLE.yaml -new file mode 100644 -index 0000000..ea66754 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_UNALIGNED_ACCESSES_POSSIBLE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_USE_UNALIGNED_ACCESSES_POSSIBLE -+introduced: 1.0.0 -+removed: 1.4.0 -+default: false -+tags: -+ - portability -+description: > -+ Target architecture unaligned memory accesses (e.g. 32-bit integer access -+ from an arbitrary address). -diff --git a/dist/source/config/config-options/DUK_USE_UNDERSCORE_SETJMP.yaml b/dist/source/config/config-options/DUK_USE_UNDERSCORE_SETJMP.yaml -new file mode 100644 -index 0000000..39a0420 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_UNDERSCORE_SETJMP.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_UNDERSCORE_SETJMP -+introduced: 1.1.0 -+removed: 1.5.0 -+default: false -+tags: -+ - portability -+description: > -+ Use _setjmp/_longjmp for long control transfers. This ensures signal -+ mask is not saved which can be a lot faster if setjmp/longjmp saves the -+ signal mask (this varies between platforms). See comments in -+ DUK_USE_SETJMP. -+ -+ Removed in Duktape 1.5.0: edit duk_config.h directly. -diff --git a/dist/source/config/config-options/DUK_USE_UNION_INITIALIZERS.yaml b/dist/source/config/config-options/DUK_USE_UNION_INITIALIZERS.yaml -new file mode 100644 -index 0000000..4cd5424 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_UNION_INITIALIZERS.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_UNION_INITIALIZERS -+introduced: 1.5.0 -+default: false -+tags: -+ - portability -+description: > -+ Compiler supports C99-style designated union initializers, e.g. -+ { .foo = 123 }. -+ -+ When disabled, Duktape sometimes needs to resort to less efficient struct -+ initializers for portability. -diff --git a/dist/source/config/config-options/DUK_USE_USER_DECLARE.yaml b/dist/source/config/config-options/DUK_USE_USER_DECLARE.yaml -new file mode 100644 -index 0000000..9393909 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_USER_DECLARE.yaml -@@ -0,0 +1,17 @@ -+define: DUK_USE_USER_DECLARE -+introduced: 1.0.0 -+removed: 2.4.0 -+default: -+ verbatim: '#define DUK_USE_USER_DECLARE() /* no user declarations */' -+tags: -+ - portability -+description: > -+ Provide declarations or additional preprocessor include directives to be -+ used when compiling Duktape. You may need this if you set -+ DUK_USE_PANIC_HANDLER to call your own panic handler function. You can -+ also use this option to cause additional files to be included when compiling -+ Duktape. -+ -+ NOTE: This is only needed if using the default autodetecting duk_config.h -+ header. When providing DUK_USE_xxx flags directly, you should just provide -+ all the necessary declarations in duk_config.h directly. -diff --git a/dist/source/config/config-options/DUK_USE_USER_INITJS.yaml b/dist/source/config/config-options/DUK_USE_USER_INITJS.yaml -new file mode 100644 -index 0000000..cb39223 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_USER_INITJS.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_USER_INITJS -+introduced: 1.0.0 -+removed: 2.0.0 -+default: false -+tags: -+ - portability -+description: > -+ Provide a string to evaluate when a thread with new built-ins (a new global -+ environment) is created. This allows you to make minor modifications to the -+ global environment before any code is executed in it. The value must be a -+ string, e.g.:: -DDUK_OPT_USER_INITJS='"this.foo = 123"'. -+ -+ Errors in the initialization code result in a fatal error. -diff --git a/dist/source/config/config-options/DUK_USE_VALSTACK_GROW_SHIFT.yaml b/dist/source/config/config-options/DUK_USE_VALSTACK_GROW_SHIFT.yaml -new file mode 100644 -index 0000000..3f122a5 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VALSTACK_GROW_SHIFT.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_VALSTACK_GROW_SHIFT -+introduced: 2.2.0 -+default: 2 -+tags: -+ - performance -+ - lowmemory -+description: > -+ When growing the value stack, shift minimum size right by this amount to -+ come up with a slack which is allocated on top of the minimum required -+ size. The slack increases memory usage a bit, but reduces value stack -+ reallocations when the minimum size grows. A value of 2 means that a -+ 25% slack is used. Undefine to remove any slack, value stack is then -+ always grown by the minimum amount possible. -diff --git a/dist/source/config/config-options/DUK_USE_VALSTACK_LIMIT.yaml b/dist/source/config/config-options/DUK_USE_VALSTACK_LIMIT.yaml -new file mode 100644 -index 0000000..da9c352 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VALSTACK_LIMIT.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_VALSTACK_LIMIT -+introduced: 2.2.0 -+default: 1000000 -+tags: -+ - misc -+description: > -+ Maximum value stack size. If value stack is about to be grown beyond this -+ size (the check includes a possible spare so the check isn't exact) reject -+ the resize. The limit must be low enough so that when multiplied by -+ sizeof(duk_tval), typically 8 or 16, the multiplication won't overflow -+ size_t. -diff --git a/dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT.yaml b/dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT.yaml -new file mode 100644 -index 0000000..a06162a ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT.yaml -@@ -0,0 +1,13 @@ -+define: DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT -+introduced: 2.2.0 -+default: 2 -+tags: -+ - performance -+ - lowmemory -+description: > -+ When doing a value stack shrink check, skip shrinking if the difference -+ between the minimum reserve and allocated size is less than -+ (curr_size >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT) bytes. A value of 2 -+ means that the difference must be at least 25% for a shrink to happen. -+ If undefined, value stack is always shrunk to the minimum reserved size -+ with no slack. -diff --git a/dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT.yaml b/dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT.yaml -new file mode 100644 -index 0000000..341e445 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT -+introduced: 2.2.0 -+default: 4 -+tags: -+ - performance -+ - lowmemory -+description: > -+ When shrinking, leave (curr_size >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT) -+ bytes as a slack. This shift count must be larger than -+ DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT. -diff --git a/dist/source/config/config-options/DUK_USE_VALSTACK_UNSAFE.yaml b/dist/source/config/config-options/DUK_USE_VALSTACK_UNSAFE.yaml -new file mode 100644 -index 0000000..4c0f881 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VALSTACK_UNSAFE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_VALSTACK_UNSAFE -+introduced: 1.2.0 -+default: false -+tags: -+ - performance -+ - experimental -+description: > -+ Don't check allocated value stack size in operations like value stack -+ pushes. Improves performance of API calls but causes unsafe memory -+ behavior (e.g. a segfault) when user code pushes beyond "checked" value -+ stack size. -diff --git a/dist/source/config/config-options/DUK_USE_VARIADIC_MACROS.yaml b/dist/source/config/config-options/DUK_USE_VARIADIC_MACROS.yaml -new file mode 100644 -index 0000000..be08169 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VARIADIC_MACROS.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_VARIADIC_MACROS -+introduced: 1.0.0 -+default: true -+tags: -+ - portability -+description: > -+ Compiler supports C99-style variadic macros. Highly recommended to enable -+ when possible. -+ -+ When disabled, Duktape needs to resort to various hacks to work around -+ missing support for variadic macros. -diff --git a/dist/source/config/config-options/DUK_USE_VERBOSE_ERRORS.yaml b/dist/source/config/config-options/DUK_USE_VERBOSE_ERRORS.yaml -new file mode 100644 -index 0000000..d5c7b12 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VERBOSE_ERRORS.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_VERBOSE_ERRORS -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Provide error message strings and file/line information for errors generated -+ by Duktape. -+ -+ When disabled, reduces footprint at the cost of much less informative -+ ECMAScript errors. -diff --git a/dist/source/config/config-options/DUK_USE_VERBOSE_EXECUTOR_ERRORS.yaml b/dist/source/config/config-options/DUK_USE_VERBOSE_EXECUTOR_ERRORS.yaml -new file mode 100644 -index 0000000..a23cc9c ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VERBOSE_EXECUTOR_ERRORS.yaml -@@ -0,0 +1,10 @@ -+define: DUK_USE_VERBOSE_EXECUTOR_ERRORS -+introduced: 1.0.0 -+default: true -+tags: -+ - ecmascript -+description: > -+ Use verbose error messages in bytecode executor (recommended). -+ -+ When disabled, reduces footprint slightly at the cost of more obscure -+ error messages. -diff --git a/dist/source/config/config-options/DUK_USE_VOLUNTARY_GC.yaml b/dist/source/config/config-options/DUK_USE_VOLUNTARY_GC.yaml -new file mode 100644 -index 0000000..530df47 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_VOLUNTARY_GC.yaml -@@ -0,0 +1,16 @@ -+define: DUK_USE_VOLUNTARY_GC -+introduced: 1.0.0 -+default: true -+tags: -+ - gc -+ - memory -+description: > -+ Enable voluntary periodic mark-and-sweep collection. -+ -+ When disabled, a mark-and-sweep collection is still triggered in an -+ out-of-memory condition (known as "emergency GC". When disabling this -+ option it's recommended to use reference counting which collects all -+ non-cyclical garbage. Application code should also request an explicit -+ garbage collection from time to time when appropriate. When this option -+ is disabled, Duktape will have no garbage collection pauses in ordinary -+ use, which is useful for timing sensitive applications like games. -diff --git a/dist/source/config/config-options/DUK_USE_ZERO_BUFFER_DATA.yaml b/dist/source/config/config-options/DUK_USE_ZERO_BUFFER_DATA.yaml -new file mode 100644 -index 0000000..4015c93 ---- /dev/null -+++ b/dist/source/config/config-options/DUK_USE_ZERO_BUFFER_DATA.yaml -@@ -0,0 +1,11 @@ -+define: DUK_USE_ZERO_BUFFER_DATA -+introduced: 1.0.0 -+default: true -+tags: -+ - memory -+ - ecmascript -+description: > -+ Zero data are of newly allocated buffer values (recommended). -+ -+ When disabled, buffers are not zeroed and may contain arbitrary data. -+ Disabling this option only makes sense for performance reasons. -diff --git a/dist/source/config/examples/compliance.yaml b/dist/source/config/examples/compliance.yaml -new file mode 100644 -index 0000000..018add3 ---- /dev/null -+++ b/dist/source/config/examples/compliance.yaml -@@ -0,0 +1,18 @@ -+# Enable compliant behavior, defaults favor "real world" compatibility. -+ -+DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT: false -+DUK_USE_NONSTD_FUNC_CALLER_PROPERTY: false -+DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY: false -+DUK_USE_NONSTD_FUNC_STMT: false -+DUK_USE_NONSTD_GETTER_KEY_ARGUMENT: false -+DUK_USE_NONSTD_JSON_ESC_U2028_U2029: false -+DUK_USE_NONSTD_SETTER_KEY_ARGUMENT: false -+DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT: false -+DUK_USE_ES6_REGEXP_SYNTAX: false # for ES5 compliance, disable ES6-only regexp extra syntax -+ -+# These Array fast paths assume Array.prototype has no inherited index -+# properties which might affect reads/writes. Such properties are very -+# rare so this assumption is usually a good one; for strict compliance, -+# disable the fast paths. -+DUK_USE_ARRAY_PROP_FASTPATH: false -+DUK_USE_ARRAY_FASTPATH: false -diff --git a/dist/source/config/examples/debugger_support.yaml b/dist/source/config/examples/debugger_support.yaml -new file mode 100644 -index 0000000..4986adc ---- /dev/null -+++ b/dist/source/config/examples/debugger_support.yaml -@@ -0,0 +1,24 @@ -+# Enable debugger support in general, also needs interrupt support. -+DUK_USE_INTERRUPT_COUNTER: true -+DUK_USE_DEBUGGER_SUPPORT: true -+ -+# Basic set of Notifys. -+DUK_USE_DEBUGGER_THROW_NOTIFY: true -+ -+# Automatically pause on an uncaught error about to be thrown. -+DUK_USE_DEBUGGER_PAUSE_UNCAUGHT: true -+ -+# Enable DumpHeap command (experimental). -+DUK_USE_DEBUGGER_DUMPHEAP: true -+ -+# Enable object inspection commands: GetHeapObjInfo, GetObjPropDesc, -+# GetObjPropDescRange. -+DUK_USE_DEBUGGER_INSPECT: true -+ -+# Transport torture testing: enable when testing your transport -+# implementation. -+DUK_USE_DEBUGGER_TRANSPORT_TORTURE: false -+ -+# NOTE: If you're using the Duktape command line utility for debugging -+# (duk --debugger ...), remember to enable debugger support for the command -+# line tool when compiling it: -DDUK_CMDLINE_DEBUGGER_SUPPORT. -diff --git a/dist/source/config/examples/disable_bufferobjects.yaml b/dist/source/config/examples/disable_bufferobjects.yaml -new file mode 100644 -index 0000000..23b85a8 ---- /dev/null -+++ b/dist/source/config/examples/disable_bufferobjects.yaml -@@ -0,0 +1,3 @@ -+# Disable support for typed arrays and Node.js Buffer. Duktape will still -+# support plain buffers and Duktape.Buffer. -+DUK_USE_BUFFEROBJECT_SUPPORT: false -diff --git a/dist/source/config/examples/disable_es6.yaml b/dist/source/config/examples/disable_es6.yaml -new file mode 100644 -index 0000000..26c3411 ---- /dev/null -+++ b/dist/source/config/examples/disable_es6.yaml -@@ -0,0 +1,5 @@ -+# Disable ES2015 features. -+ -+DUK_USE_ES6_OBJECT_PROTO_PROPERTY: false -+DUK_USE_ES6_OBJECT_SETPROTOTYPEOFS: false -+DUK_USE_ES6_PROXY: false -diff --git a/dist/source/config/examples/enable_debug_print0.yaml b/dist/source/config/examples/enable_debug_print0.yaml -new file mode 100644 -index 0000000..1f8392e ---- /dev/null -+++ b/dist/source/config/examples/enable_debug_print0.yaml -@@ -0,0 +1,3 @@ -+# Enable debug level 0. -+DUK_USE_DEBUG: true -+DUK_USE_DEBUG_LEVEL: 0 -diff --git a/dist/source/config/examples/enable_debug_print1.yaml b/dist/source/config/examples/enable_debug_print1.yaml -new file mode 100644 -index 0000000..00f3c7e ---- /dev/null -+++ b/dist/source/config/examples/enable_debug_print1.yaml -@@ -0,0 +1,3 @@ -+# Enable debug level 1. -+DUK_USE_DEBUG: true -+DUK_USE_DEBUG_LEVEL: 1 -diff --git a/dist/source/config/examples/enable_debug_print2.yaml b/dist/source/config/examples/enable_debug_print2.yaml -new file mode 100644 -index 0000000..45ac617 ---- /dev/null -+++ b/dist/source/config/examples/enable_debug_print2.yaml -@@ -0,0 +1,3 @@ -+# Enable debug level 2. -+DUK_USE_DEBUG: true -+DUK_USE_DEBUG_LEVEL: 2 -diff --git a/dist/source/config/examples/enable_fastint.yaml b/dist/source/config/examples/enable_fastint.yaml -new file mode 100644 -index 0000000..16ff5c9 ---- /dev/null -+++ b/dist/source/config/examples/enable_fastint.yaml -@@ -0,0 +1,3 @@ -+# Enable fastint support. -+ -+DUK_USE_FASTINT: true -diff --git a/dist/source/config/examples/low_memory.yaml b/dist/source/config/examples/low_memory.yaml -new file mode 100644 -index 0000000..6059b32 ---- /dev/null -+++ b/dist/source/config/examples/low_memory.yaml -@@ -0,0 +1,158 @@ -+# Base configuration for low memory environments, see -+# doc/low-memory.rst: -+# -+# - Strips verbose errors etc -+# - Strips some ES2015 features like Proxy support (re-enable if needed) -+# - Strips some Duktape custom feature like JX/JC; keeps e.g. RegExp -+# and other standard parts -+# - Strips some commonly unnecessary API calls like bytecode dump/load -+# - Does not enable pointer compression or external strings: these -+# need target specific support code -+# - Does not enable ROM string/object support by default, enable manually -+# -+ -+# Consider switching alignment to align-by-1 or align-by-4 for more compact -+# memory layout if the architecture supports it. -+#DUK_USE_ALIGN_BY: 1 -+ -+# With the vast majority of compilers some of the 'undefined behavior' -+# assumptions are fine, and produce smaller and faster code, so enable -+# by default for lowmem targets. You may need to disable this for some -+# compilers. -+DUK_USE_ALLOW_UNDEFINED_BEHAVIOR: true -+ -+DUK_USE_PREFER_SIZE: true -+DUK_USE_EXEC_PREFER_SIZE: true -+DUK_USE_FAST_REFCOUNT_DEFAULT: false -+DUK_USE_AUGMENT_ERROR_CREATE: false -+DUK_USE_AUGMENT_ERROR_THROW: false -+DUK_USE_TRACEBACKS: false -+DUK_USE_ERRCREATE: false -+DUK_USE_ERRTHROW: false -+DUK_USE_VERBOSE_ERRORS: false -+DUK_USE_PARANOID_ERRORS: true -+DUK_USE_FATAL_MAXLEN: 64 -+DUK_USE_VERBOSE_EXECUTOR_ERRORS: false # <100 bytes footprint -+DUK_USE_DEBUGGER_SUPPORT: false # must be disabled if DUK_USE_PC2LINE is disabled -+DUK_USE_PC2LINE: false -+DUK_USE_LEXER_SLIDING_WINDOW: false -+DUK_USE_JSON_STRINGIFY_FASTPATH: false -+DUK_USE_JSON_QUOTESTRING_FASTPATH: false -+DUK_USE_JSON_DECSTRING_FASTPATH: false -+DUK_USE_JSON_DECNUMBER_FASTPATH: false -+DUK_USE_JSON_EATWHITE_FASTPATH: false -+DUK_USE_BASE64_FASTPATH: false -+DUK_USE_HEX_FASTPATH: false -+DUK_USE_IDCHAR_FASTPATH: false -+DUK_USE_ARRAY_PROP_FASTPATH: false -+DUK_USE_ARRAY_FASTPATH: false -+DUK_USE_BYTECODE_DUMP_SUPPORT: false -+DUK_USE_JX: false -+DUK_USE_JC: false -+#DUK_USE_REGEXP_SUPPORT: false -+DUK_USE_DEBUG_BUFSIZE: 2048 -+DUK_USE_LIGHTFUNC_BUILTINS: true -+ -+# Grow value stack without any slack, and shrink to minimum reserved size with -+# no slack. Increases allocation traffic but avoids allocating space not -+# actually needed. -+DUK_USE_VALSTACK_GROW_SHIFT: false -+DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT: false -+DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT: false -+ -+# Using the same minsize and maxsize drops code footprint by around 400 bytes -+# (string table resize code is omitted). Enabling DUK_USE_STRTAB_PTRCOMP -+# saves some RAM (two bytes per strtab entry) at the cost of 200-300 bytes of -+# code footprint. -+DUK_USE_STRTAB_MINSIZE: 128 -+DUK_USE_STRTAB_MAXSIZE: 128 -+DUK_USE_STRTAB_SHRINK_LIMIT: 0 # doesn't matter if minsize==masize -+DUK_USE_STRTAB_GROW_LIMIT: 65536 # -""- -+DUK_USE_STRTAB_RESIZE_CHECK_MASK: 255 # -""- -+#DUK_USE_STRTAB_PTRCOMP: true # sometimes useful with pointer compression -+ -+# Disable literal pinning and litcache. -+DUK_USE_LITCACHE_SIZE: false -+ -+DUK_USE_HSTRING_ARRIDX: false -+DUK_USE_HSTRING_LAZY_CLEN: false # non-lazy charlen is smaller -+ -+# Only add a hash table for quite large objects to conserve memory. Even -+# lower memory targets usually drop hash part support entirely. -+DUK_USE_HOBJECT_HASH_PROP_LIMIT: 64 -+ -+DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE: 32 -+ -+# Disable freelist caching. -+DUK_USE_CACHE_ACTIVATION: false -+DUK_USE_CACHE_CATCHER: false -+ -+# Consider using pointer compression, see doc/low-memory.rst. -+#DUK_USE_REFCOUNT16: true -+#DUK_USE_REFCOUNT32: false -+#DUK_USE_STRHASH16: true -+#DUK_USE_STRLEN16: true -+#DUK_USE_BUFLEN16: true -+#DUK_USE_OBJSIZES16: true -+#DUK_USE_HSTRING_CLEN: false -+#DUK_USE_HSTRING_LAZY_CLEN: false -+#DUK_USE_HOBJECT_HASH_PART: false -+#DUK_USE_HEAPPTR16 -+#DUK_USE_HEAPPTR_DEC16 -+#DUK_USE_HEAPPTR_ENC16 -+ -+# Consider using external strings, see doc/low_memory.rst. -+#DUK_USE_EXTERNAL_STRINGS: true -+#DUK_USE_EXTSTR_INTERN_CHECK -+#DUK_USE_EXTSTR_FREE -+ -+# Consider removing Node.js Buffer and ES2015 typed array support if not -+# needed (about 10 kB code footprint difference on x64) -+DUK_USE_BUFFEROBJECT_SUPPORT: false -+ -+# Consider to reduce code footprint at the expense of more erratic RAM usage -+#DUK_USE_REFERENCE_COUNTING: false -+#DUK_USE_DOUBLE_LINKED_HEAP: false -+ -+# Consider to reduce code footprint at the expense of less safeguards against -+# bugs in calling C code. -+DUK_USE_VALSTACK_UNSAFE: true -+ -+# Disable optimizations for case insensitive regexps. If code involves -+# case insensitive regexps with large character classes, consider enabling -+# at least DUK_USE_REGEXP_CANON_BITMAP. -+DUK_USE_REGEXP_CANON_WORKAROUND: false # very large footprint (~128kB) -+DUK_USE_REGEXP_CANON_BITMAP: false # small footprint (~300-400 bytes) -+ -+# Consider using ROM strings/objects to reduce footprint, see doc/low_memory.rst. -+# ROM strings/objects reduce startup RAM usage at the expense of code footprint -+# and some compliance. -+#DUK_USE_ROM_STRINGS: true -+#DUK_USE_ROM_OBJECTS: true -+#DUK_USE_ROM_GLOBAL_INHERIT: true # select inherit or clone; inherit recommended -+#DUK_USE_ROM_GLOBAL_CLONE: false -+ -+# Function footprint size reduction. -+DUK_USE_FUNC_NAME_PROPERTY: true # compliance -+DUK_USE_FUNC_FILENAME_PROPERTY: false # non-standard, can be removed -+ -+# Consider these; disabled by default because they don't impact E5 compliance. -+DUK_USE_ES6: false -+DUK_USE_ES7: false -+DUK_USE_ES8: false -+DUK_USE_ES9: false -+DUK_USE_BASE64_SUPPORT: false -+DUK_USE_HEX_SUPPORT: false -+DUK_USE_COROUTINE_SUPPORT: false -+DUK_USE_SOURCE_NONBMP: false # <300 bytes footprint -+DUK_USE_ES6_PROXY: false # roughly 2kB footprint -+DUK_USE_ES7_EXP_OPERATOR: false # pulls in pow() -+DUK_USE_ENCODING_BUILTINS: false -+DUK_USE_PERFORMANCE_BUILTIN: false -+DUK_USE_ES6_UNICODE_ESCAPE: false -+DUK_USE_HTML_COMMENTS: false -+DUK_USE_SHEBANG_COMMENTS: false -+DUK_USE_REFLECT_BUILTIN: false -+DUK_USE_SYMBOL_BUILTIN: false -+DUK_USE_CBOR_SUPPORT: false -+DUK_USE_CBOR_BUILTIN: false -diff --git a/dist/source/config/examples/low_memory_strip.yaml b/dist/source/config/examples/low_memory_strip.yaml -new file mode 100644 -index 0000000..1aefac1 ---- /dev/null -+++ b/dist/source/config/examples/low_memory_strip.yaml -@@ -0,0 +1,49 @@ -+# More stripping for low memory environments, removing e.g. RegExp support, -+# coroutine support, etc. -+ -+DUK_USE_BUFFEROBJECT_SUPPORT: false -+ -+DUK_USE_REGEXP_SUPPORT: false -+ -+DUK_USE_REFERENCE_COUNTING: false -+DUK_USE_DOUBLE_LINKED_HEAP: false -+ -+# Consider to reduce code footprint at the expense of less safeguards against -+# bugs in calling C code -+DUK_USE_VALSTACK_UNSAFE: true -+ -+# Short term workaround with large footprint, disable. -+DUK_USE_REGEXP_CANON_WORKAROUND: false -+ -+# Coroutine support has about 2kB footprint. -+DUK_USE_COROUTINE_SUPPORT: false -+ -+# Finalizer support has about 0.8kB footprint. -+DUK_USE_FINALIZER_SUPPORT: false -+ -+# ES2015 Proxy has about 2kB footprint. -+DUK_USE_ES6_PROXY: false -+ -+# Don't support non-BMP characters in source code (UTF-8 otherwise OK). -+DUK_USE_SOURCE_NONBMP: false -+ -+# Don't include even .name property for functions. -+DUK_USE_FUNC_NAME_PROPERTY: false -+ -+# Remove built-in bindings. -+DUK_USE_MATH_BUILTIN: false -+DUK_USE_DATE_BUILTIN: false -+DUK_USE_ARRAY_BUILTIN: false -+DUK_USE_STRING_BUILTIN: false -+DUK_USE_BOOLEAN_BUILTIN: false -+DUK_USE_NUMBER_BUILTIN: false -+DUK_USE_FUNCTION_BUILTIN: false -+DUK_USE_OBJECT_BUILTIN: false -+DUK_USE_DUKTAPE_BUILTIN: false -+DUK_USE_JSON_BUILTIN: false -+DUK_USE_ENCODING_BUILTINS: false -+DUK_USE_REFLECT_BUILTIN: false -+DUK_USE_JSON_SUPPORT: false # also disables JSON support for C API -+DUK_USE_GLOBAL_BUILTIN: false -+DUK_USE_CBOR_SUPPORT: false -+DUK_USE_CBOR_BUILTIN: false -diff --git a/dist/source/config/examples/performance_sensitive.yaml b/dist/source/config/examples/performance_sensitive.yaml -new file mode 100644 -index 0000000..f1da1e4 ---- /dev/null -+++ b/dist/source/config/examples/performance_sensitive.yaml -@@ -0,0 +1,38 @@ -+# Base configuration for performance sensitive environments, see -+# doc/performance-sensitive.rst. -+ -+# You should choose the fastest setjmp/longjmp for your platform. -+ -+# With the vast majority of compilers some of the 'undefined behavior' -+# assumptions are fine, and produce smaller and faster code, so enable -+# by default for performance oriented targets. You may need to disable -+# this for some compilers. -+DUK_USE_ALLOW_UNDEFINED_BEHAVIOR: true -+ -+DUK_USE_PREFER_SIZE: false -+DUK_USE_PACKED_TVAL: false # packed duk_tval slower in most cases -+DUK_USE_FASTINT: true -+DUK_USE_VALSTACK_UNSAFE: true -+DUK_USE_FAST_REFCOUNT_DEFAULT: true -+ -+DUK_USE_JSON_STRINGIFY_FASTPATH: true # not fully portable right now -+DUK_USE_JSON_QUOTESTRING_FASTPATH: true -+DUK_USE_JSON_DECSTRING_FASTPATH: true -+DUK_USE_JSON_DECNUMBER_FASTPATH: true -+DUK_USE_JSON_EATWHITE_FASTPATH: true -+DUK_USE_BASE64_FASTPATH: true -+DUK_USE_HEX_FASTPATH: true -+DUK_USE_IDCHAR_FASTPATH: true -+DUK_USE_ARRAY_PROP_FASTPATH: true -+DUK_USE_ARRAY_FASTPATH: true -+DUK_USE_INTERRUPT_COUNTER: false -+ -+DUK_USE_DEBUGGER_SUPPORT: false -+ -+DUK_USE_STRHASH_DENSE: false -+DUK_USE_STRHASH_SKIP_SHIFT: 5 # may be able to reduce -+#DUK_USE_EXEC_FUN_LOCAL: false # test both values, marginal benefit -+ -+DUK_USE_LITCACHE_SIZE: 1024 -+ -+DUK_USE_REGEXP_CANON_WORKAROUND: true # high footprint impact (128kB), enabled until a better solution -diff --git a/dist/source/config/examples/rom_builtins.yaml b/dist/source/config/examples/rom_builtins.yaml -new file mode 100644 -index 0000000..a5ba4a8 ---- /dev/null -+++ b/dist/source/config/examples/rom_builtins.yaml -@@ -0,0 +1,19 @@ -+# Move built-in strings and objects to ROM (read-only data section) to reduce -+# RAM usage of Duktape heaps; all heaps will share the same built-in strings -+# and objects, except for the global object which is writable. The downside -+# is that built-in objects (other than global object) will be read-only. -+ -+# These should be used together. -+DUK_USE_ROM_STRINGS: true -+DUK_USE_ROM_OBJECTS: true -+ -+# Provide a writable global object: -+# - DUK_USE_ROM_GLOBAL_INHERIT: empty RAM global object inherits from ROM -+# global object, uses very little RAM. -+# - DUK_USE_ROM_GLOBAL_CLONE: ROM global object is cloned into RAM, more -+# compliant but uses more RAM. -+# -+# If both are set to 'false', global object will be non-writable which -+# may surprise users. -+DUK_USE_ROM_GLOBAL_INHERIT: true -+DUK_USE_ROM_GLOBAL_CLONE: false -diff --git a/dist/source/config/examples/security_sensitive.yaml b/dist/source/config/examples/security_sensitive.yaml -new file mode 100644 -index 0000000..bdcbb81 ---- /dev/null -+++ b/dist/source/config/examples/security_sensitive.yaml -@@ -0,0 +1,17 @@ -+# Base configuration for security sensitive environments. -+ -+# Avoid summary of object/key for rejected property operations. May be -+# relevant if keys contain potentially sensitive information. -+DUK_USE_PARANOID_ERRORS: true -+ -+# Disable tracebacks, minimizes attacker knowledge of call chains. Access -+# to the internal error _Tracedata property provides access to all functions -+# in the call chain (even when they're otherwise not visible to sandboxed -+# code). -+DUK_USE_TRACEBACKS: false -+ -+# Dense string hashing may be useful against accidental string hash collisions. -+# This won't prevent an attacker from finding intentional collisions. -+DUK_USE_STRHASH_DENSE: true -+ -+# TBD -diff --git a/dist/source/config/examples/shallow_c_stack.yaml b/dist/source/config/examples/shallow_c_stack.yaml -new file mode 100644 -index 0000000..4bbf8b4 ---- /dev/null -+++ b/dist/source/config/examples/shallow_c_stack.yaml -@@ -0,0 +1,10 @@ -+# Reduce recursion limits for shallow C stack targets. -+# These values are based on the (removed) DUK_USE_DEEP_C_STACK option. -+ -+DUK_USE_NATIVE_CALL_RECLIMIT: 60 -+DUK_USE_COMPILER_RECLIMIT: 50 -+DUK_USE_REGEXP_COMPILER_RECLIMIT: 100 -+DUK_USE_REGEXP_EXECUTOR_RECLIMIT: 100 -+DUK_USE_JSON_ENC_RECLIMIT: 100 -+DUK_USE_JSON_DEC_RECLIMIT: 100 -+DUK_USE_MARK_AND_SWEEP_RECLIMIT: 32 -diff --git a/dist/source/config/examples/timing_sensitive.yaml b/dist/source/config/examples/timing_sensitive.yaml -new file mode 100644 -index 0000000..dd11081 ---- /dev/null -+++ b/dist/source/config/examples/timing_sensitive.yaml -@@ -0,0 +1,6 @@ -+# Base configuration for timing sensitive environments, see -+# doc/timing-sensitive.rst: -+ -+DUK_USE_MARK_AND_SWEEP: true -+DUK_USE_REFERENCE_COUNTING: true -+DUK_USE_VOLUNTARY_GC: false -diff --git a/dist/source/config/feature-options/DUK_OPT_ASSERTIONS.yaml b/dist/source/config/feature-options/DUK_OPT_ASSERTIONS.yaml -new file mode 100644 -index 0000000..497c2cc ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_ASSERTIONS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_ASSERTIONS -+introduced: 1.0.0 -+tags: -+ - development -+ - debug -+description: > -+ Enable internal assert checks. These slow down execution considerably -+ so only use when debugging. -diff --git a/dist/source/config/feature-options/DUK_OPT_BUFFEROBJECT_SUPPORT.yaml b/dist/source/config/feature-options/DUK_OPT_BUFFEROBJECT_SUPPORT.yaml -new file mode 100644 -index 0000000..1cb1dae ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_BUFFEROBJECT_SUPPORT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_BUFFEROBJECT_SUPPORT -+introduced: 1.3.0 -+tags: -+ - ecmascript6 -+description: > -+ Enable support for Khronos/ES6 typed arrays and Node.js Buffer objects. -+ This adds about 8-9 kB of code footprint on x64. When disabled, Duktape -+ custom plain buffers and Duktape.Buffer are still supported. -diff --git a/dist/source/config/feature-options/DUK_OPT_BUFLEN16.yaml b/dist/source/config/feature-options/DUK_OPT_BUFLEN16.yaml -new file mode 100644 -index 0000000..682b1f7 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_BUFLEN16.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_BUFLEN16 -+introduced: 1.1.0 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit buffer length field (for low memory environments). -diff --git a/dist/source/config/feature-options/DUK_OPT_DATAPTR16.yaml b/dist/source/config/feature-options/DUK_OPT_DATAPTR16.yaml -new file mode 100644 -index 0000000..e86d313 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DATAPTR16.yaml -@@ -0,0 +1,20 @@ -+define: DUK_OPT_DATAPTR16 -+introduced: 1.1.0 -+related: -+ - DUK_OPT_DATAPTR_ENC16 -+ - DUK_OPT_DATAPTR_DEC16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable "compression" of arbitrary data pointers into an unsigned 16-bit -+ value. Use together with DUK_OPT_DATAPTR_ENC16 and DUK_OPT_DATAPTR_DEC16. -+ -+ Pointers compressed are any void pointers in C code, not just the Duktape -+ heap. Also NULL pointer must encode and decode correctly. -+ -+ Currently it is required that NULL encodes to integer 0, and integer -+ 0 decodes to NULL. No other pointer can be encoded to 0. -+ -+ NOTE: This feature option is currently unimplemented, i.e. Duktape won't -+ compress any data pointers at the moment. -diff --git a/dist/source/config/feature-options/DUK_OPT_DATAPTR_DEC16.yaml b/dist/source/config/feature-options/DUK_OPT_DATAPTR_DEC16.yaml -new file mode 100644 -index 0000000..9a1c693 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DATAPTR_DEC16.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_DATAPTR_DEC16 -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_DATAPTR16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_OPT_DATAPTR16 for arbitrary data pointer compression. -+ DUK_OPT_DATAPTR_DEC16(udata,x) is a macro with a userdata and duk_uint16_t -+ argument, and a void ptr return value. The userdata argument is the heap -+ userdata value given at heap creation. -diff --git a/dist/source/config/feature-options/DUK_OPT_DATAPTR_ENC16.yaml b/dist/source/config/feature-options/DUK_OPT_DATAPTR_ENC16.yaml -new file mode 100644 -index 0000000..14684bf ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DATAPTR_ENC16.yaml -@@ -0,0 +1,14 @@ -+define: DUK_OPT_DATAPTR_ENC16 -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_DATAPTR16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_OPT_DATAPTR16 for arbitrary data pointer compression. -+ DUK_OPT_DATAPTR_ENC16(udata,p) is a macro with a userdata and void ptr -+ argument, and a duk_uint16_t return value. The userdata argument is the -+ heap userdata value given at heap creation. Currently it is required that -+ NULL encodes to integer 0, and integer 0 decodes to NULL. No other pointer -+ can be encoded to 0. -diff --git a/dist/source/config/feature-options/DUK_OPT_DDDPRINT.yaml b/dist/source/config/feature-options/DUK_OPT_DDDPRINT.yaml -new file mode 100644 -index 0000000..ebdc0d5 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DDDPRINT.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_DDDPRINT -+introduced: 1.0.0 -+requires: -+ - DUK_OPT_DEBUG -+tags: -+ - debug -+description: > -+ Enable even more debug printouts. Not recommended unless you have -+ grep handy. -diff --git a/dist/source/config/feature-options/DUK_OPT_DDPRINT.yaml b/dist/source/config/feature-options/DUK_OPT_DDPRINT.yaml -new file mode 100644 -index 0000000..26b7699 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DDPRINT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_DDPRINT -+introduced: 1.0.0 -+requires: -+ - DUK_OPT_DEBUG -+tags: -+ - debug -+description: > -+ Enable more debug printouts. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEBUG.yaml b/dist/source/config/feature-options/DUK_OPT_DEBUG.yaml -new file mode 100644 -index 0000000..9c68c77 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEBUG.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_DEBUG -+introduced: 1.0.0 -+tags: -+ - debug -+description: > -+ Enable debug code in Duktape internals. Without this option other -+ debugging options (such as DUK_OPT_DPRINT) have no effect. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEBUGGER_DUMPHEAP.yaml b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_DUMPHEAP.yaml -new file mode 100644 -index 0000000..d501ce8 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_DUMPHEAP.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_DEBUGGER_DUMPHEAP -+introduced: 1.2.0 -+requires: -+ - DUK_OPT_DEBUGGER_SUPPORT -+tags: -+ - debugger -+description: > -+ Support the DumpHeap command. This is optional because the command is not -+ always needed. The command also has a relatively large footprint (about -+ 10% of debugger code); in absolute terms it's about 1kB of code footprint. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_LOGGING.yaml b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_LOGGING.yaml -new file mode 100644 -index 0000000..87497d7 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_LOGGING.yaml -@@ -0,0 +1,11 @@ -+define: DUK_OPT_DEBUGGER_FWD_LOGGING -+introduced: 1.2.0 -+requires: -+ - DUK_OPT_DEBUGGER_SUPPORT -+tags: -+ - debugger -+description: > -+ Forward log writes using the built-in logging framework to the debug client. -+ Forwarding happens from the Duktape.Logger.prototype.info() etc calls before -+ the raw() function is called, so that logging is forwarded even if you -+ replace the backend. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_PRINTALERT.yaml b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_PRINTALERT.yaml -new file mode 100644 -index 0000000..afb5e64 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_FWD_PRINTALERT.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_DEBUGGER_FWD_PRINTALERT -+introduced: 1.2.0 -+requires: -+ - DUK_OPT_DEBUGGER_SUPPORT -+tags: -+ - debugger -+description: > -+ Forward calls to the built-in print() and alert() function to the debug -+ client. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEBUGGER_SUPPORT.yaml b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_SUPPORT.yaml -new file mode 100644 -index 0000000..bf1d79a ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_SUPPORT.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_DEBUGGER_SUPPORT -+introduced: 1.2.0 -+requires: -+ - DUK_OPT_INTERRUPT_COUNTER -+tags: -+ - debugger -+description: > -+ Enable support for Duktape debug protocol (see doc/debugger.rst) and the -+ debug API calls (duk_debugger_attach(), duk_debugger_detach(), etc). -+ This adds about 10kB of code footprint at the moment. -+ -+ This option requires DUK_OPT_INTERRUPT_COUNTER. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEBUGGER_TRANSPORT_TORTURE.yaml b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_TRANSPORT_TORTURE.yaml -new file mode 100644 -index 0000000..0d8c858 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEBUGGER_TRANSPORT_TORTURE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_OPT_DEBUGGER_TRANSPORT_TORTURE -+introduced: 1.2.0 -+requires: -+ - DUK_OPT_DEBUGGER_SUPPORT -+tags: -+ - debugger -+ - development -+description: > -+ Development time option: force debugger transport torture. Concretely this -+ now causes Duktape to read/write debug protocol data in 1-byte increments, -+ which stresses message parsing and transport code. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEBUG_BUFSIZE.yaml b/dist/source/config/feature-options/DUK_OPT_DEBUG_BUFSIZE.yaml -new file mode 100644 -index 0000000..ae87d23 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEBUG_BUFSIZE.yaml -@@ -0,0 +1,11 @@ -+define: DUK_OPT_DEBUG_BUFSIZE -+introduced: 1.0.0 -+requires: -+ - DUK_OPT_DEBUG -+tags: -+ - debug -+description: > -+ Debug code uses a static buffer as a formatting temporary to avoid side -+ effects in debug prints. The static buffer is large by default, which -+ may be an issue in constrained environments. You can set the buffer size -+ manually with this option. Example: -DDUK_OPT_DEBUG_BUFSIZE=2048. -diff --git a/dist/source/config/feature-options/DUK_OPT_DECLARE.yaml b/dist/source/config/feature-options/DUK_OPT_DECLARE.yaml -new file mode 100644 -index 0000000..e8f766e ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DECLARE.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_DECLARE -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Provide declarations or additional preprocessor include directives to be -+ used when compiling Duktape. You may need this if you set -+ DUK_OPT_PANIC_HANDLER to call your own panic handler function. You can -+ also use this option to cause additional files to be included when compiling -+ Duktape. -diff --git a/dist/source/config/feature-options/DUK_OPT_DEEP_C_STACK.yaml b/dist/source/config/feature-options/DUK_OPT_DEEP_C_STACK.yaml -new file mode 100644 -index 0000000..7de8932 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DEEP_C_STACK.yaml -@@ -0,0 +1,15 @@ -+define: DUK_OPT_DEEP_C_STACK -+introduced: 1.0.0 -+removed: 1.3.0 -+tags: -+ - memory -+ - portability -+description: > -+ By default Duktape imposes a sanity limit on the depth of the C stack -+ because it is often limited in embedded environments. This option -+ forces Duktape to use a deep C stack which relaxes e.g. recursion limits. -+ Automatic feature detection enables deep C stacks on some platforms known -+ to have them (e.g. Linux, BSD, Windows). -+ -+ Removed in Duktape 1.3.0, use explicit config options to control recursion -+ limits for shallow stack targets. -diff --git a/dist/source/config/feature-options/DUK_OPT_DLL_BUILD.yaml b/dist/source/config/feature-options/DUK_OPT_DLL_BUILD.yaml -new file mode 100644 -index 0000000..3ec70b3 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DLL_BUILD.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_DLL_BUILD -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Add this define to both Duktape and application build when Duktape is -+ compiled as a DLL. This is especially critical on Windows: the option -+ makes Duktape use __declspec(dllexport) and __declspec(dllimport) for -+ public symbols. -+ -+ While this is not currently needed for Unix platforms, it should always -+ be used if you build as a DLL. -diff --git a/dist/source/config/feature-options/DUK_OPT_DPRINT.yaml b/dist/source/config/feature-options/DUK_OPT_DPRINT.yaml -new file mode 100644 -index 0000000..5da8a46 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DPRINT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_DPRINT -+introduced: 1.0.0 -+requires: -+ - DUK_OPT_DEBUG -+tags: -+ - debug -+description: > -+ Enable debug printouts. -diff --git a/dist/source/config/feature-options/DUK_OPT_DPRINT_COLORS.yaml b/dist/source/config/feature-options/DUK_OPT_DPRINT_COLORS.yaml -new file mode 100644 -index 0000000..6308b0b ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DPRINT_COLORS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_DPRINT_COLORS -+introduced: 1.0.0 -+tags: -+ - debug -+description: > -+ Enable coloring of debug prints with ANSI escape codes -+ (http://en.wikipedia.org/wiki/ANSI_escape_code). The behavior is not -+ sensitive to terminal settings. -diff --git a/dist/source/config/feature-options/DUK_OPT_DPRINT_RDTSC.yaml b/dist/source/config/feature-options/DUK_OPT_DPRINT_RDTSC.yaml -new file mode 100644 -index 0000000..a393d2a ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_DPRINT_RDTSC.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_DPRINT_RDTSC -+introduced: 1.0.0 -+removed: 1.4.0 -+tags: -+ - debug -+description: > -+ Print RDTSC cycle count in debug prints if available. -diff --git a/dist/source/config/feature-options/DUK_OPT_EXAMPLE.yaml b/dist/source/config/feature-options/DUK_OPT_EXAMPLE.yaml -new file mode 100644 -index 0000000..277b837 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_EXAMPLE.yaml -@@ -0,0 +1,52 @@ -+# -+# Each Duktape option is described as a YAML file named OPTION_NAME.yaml. -+# YAML is used because it diffs well and has clean support for multiline -+# inline strings. -+# -+# Metadata for feature options (DUK_OPT_xxx) is sparse, it's needed for -+# legacy support. -+# -+ -+# C #define name for the option. Must match filename minus extension. -+define: DUK_OPT_OBJSIZES16 -+ -+# Duktape version number where this option was first introduced. -+introduced: 1.1.0 -+#deprecated: 1.2.0 -+#removed: 1.3.0 -+ -+# Optional indication that feature option is defined but currently -+# unused, so that it can be omitted from generated header. -+#unused: true -+ -+# Optional list of options that must also be defined to use this option. -+#requires: -+# - DUK_OPT_FOO -+# - DUK_OPT_BAR -+ -+# Optional list of options that this option conflicts with. -+#conflicts: -+# - DUK_OPT_BAZ -+ -+# Optional list of options that are related from a user and documentation -+# perspective. -+#related: -+# - DUK_OPT_QUUX -+ -+# Tags related to option (required). If present, first tag is used as a -+# primary tag for grouping. Use 'misc' if nothing else is appropriate. -+tags: -+ - lowmemory -+ - experimental -+ -+# Description for option, no newlines. Line breaking for e.g. C header -+# is automatic. -+description: > -+ Use a 16-bit object entry and array part sizes (for low memory -+ environments). Also automatically drops support for an object hash -+ part to further reduce memory usage; there are rarely large objects -+ in low memory environments simply because there's no memory to store -+ a lot of properties. -+ -+# Marker to avoid processing this file. -+example: true -diff --git a/dist/source/config/feature-options/DUK_OPT_EXEC_TIMEOUT_CHECK.yaml b/dist/source/config/feature-options/DUK_OPT_EXEC_TIMEOUT_CHECK.yaml -new file mode 100644 -index 0000000..0e51e1f ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_EXEC_TIMEOUT_CHECK.yaml -@@ -0,0 +1,30 @@ -+define: DUK_OPT_EXEC_TIMEOUT_CHECK -+introduced: 1.2.0 -+requires: -+ - DUK_OPT_INTERRUPT_COUNTER -+tags: -+ - execution -+ - sandbox -+ - experimental -+description: > -+ NOTE: This mechanism is EXPERIMENTAL and the details may change -+ between releases. -+ -+ Provide a hook to check for bytecode execution timeout. The macro gets -+ a void ptr userdata argument (the userdata given to duk_heap_create()) -+ and must evaluate to a duk_bool_t. Duktape calls the macro as: -+ "if (DUK_OPT_EXEC_TIMEOUT_CHECK(udata)) { ... }". -+ -+ The macro is called occasionally by the Duktape bytecode executor (i.e. -+ when executing ECMAScript code), typically from a few times per second -+ to a hundred times per second, but the interval varies a great deal -+ depending on what kind of code is being executed. -+ -+ To indicate an execution timeout, the macro must return a non-zero value. -+ When that happens, Duktape starts to bubble a ``RangeError`` outwards -+ until control has been returned to the original protected call made by -+ the application. Until that happens, the exec timeout macro must always -+ return non-zero to indicate an execution timeout is still in progress. -+ -+ This mechanism and its limitations is described in more detail in -+ doc/sandboxing.rst. -diff --git a/dist/source/config/feature-options/DUK_OPT_EXTERNAL_STRINGS.yaml b/dist/source/config/feature-options/DUK_OPT_EXTERNAL_STRINGS.yaml -new file mode 100644 -index 0000000..dfb44ee ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_EXTERNAL_STRINGS.yaml -@@ -0,0 +1,11 @@ -+define: DUK_OPT_EXTERNAL_STRINGS -+introduced: 1.1.0 -+tags: -+ - memory -+description: > -+ Enable support for external strings. An external string requires a Duktape -+ heap allocation to store a minimal string header, with the actual string -+ data being held behind a pointer (similarly to how dynamic buffers work). -+ -+ This option is needed to use DUK_OPT_EXTSTR_INTERN_CHECK and/or -+ DUK_OPT_EXTSTR_FREE. -diff --git a/dist/source/config/feature-options/DUK_OPT_EXTSTR_FREE.yaml b/dist/source/config/feature-options/DUK_OPT_EXTSTR_FREE.yaml -new file mode 100644 -index 0000000..77b687d ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_EXTSTR_FREE.yaml -@@ -0,0 +1,22 @@ -+define: DUK_OPT_EXTSTR_FREE -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_EXTERNAL_STRINGS -+tags: -+ - memory -+ - experimental -+description: > -+ Optional counterpart to DUK_OPT_EXTSTR_INTERN_CHECK. Invoked when an -+ external string is about to be freed by Duktape. -+ -+ The argument "ptr" is a void ptr and points to the external string data. -+ Concretely, it is the (non-NULL) value returned by -+ DUK_OPT_EXTSTR_INTERN_CHECK. The "udata" argument is the heap userdata -+ which may be ignored if not needed. -+ -+ Also enable DUK_OPT_EXTERNAL_STRINGS to use this feature. -+ -+ NOTE: Right now there is no API to push external strings; external strings -+ come into being as a result of DUK_OPT_EXTSTR_INTERN_CHECK() only. If/when -+ this is changed, this hook will get called for every string, even if pushed -+ by the user using an API call; this may need to be rethought at that time. -diff --git a/dist/source/config/feature-options/DUK_OPT_EXTSTR_INTERN_CHECK.yaml b/dist/source/config/feature-options/DUK_OPT_EXTSTR_INTERN_CHECK.yaml -new file mode 100644 -index 0000000..0a3bea1 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_EXTSTR_INTERN_CHECK.yaml -@@ -0,0 +1,38 @@ -+define: DUK_OPT_EXTSTR_INTERN_CHECK -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_EXTERNAL_STRINGS -+tags: -+ - memory -+ - experimental -+description: > -+ Provide a hook for checking if data for a certain string can be used from -+ external memory (outside of Duktape heap, e.g. memory mapped flash). -+ The hook is called during string interning with the following semantics: -+ -+ The string data with no NUL termination resides at "ptr" and has "len" -+ bytes. The "udata" argument is the heap userdata which may be ignored -+ if not needed. If the hook returns NULL, Duktape interns the string -+ normally, i.e. string data is allocated from Duktape heap. Otherwise the -+ hook return value must point to a memory area which contains -+ "len" bytes from "ptr" followed by a NUL byte which is NOT PRESENT -+ in the input data. Data behind the returned pointer may not change after -+ the hook returns. -+ -+ The hook may be called several times for the same input string. This -+ happens when a string is interned, garbage collected, and then interned -+ again. -+ -+ The DUK_OPT_EXTSTR_FREE() hook allows application code to detect when -+ an external string is about to be freed. -+ -+ In most cases the hook should reject strings whose "len" is less than 4 -+ because there is no RAM advantage in moving so short strings into external -+ memory. The ordinary "duk_hstring" header followed by the data (and a -+ NUL byte) has the same size as "duk_hstring_external" header which hosts -+ a pointer instead of string data. -+ -+ Also enable DUK_OPT_EXTERNAL_STRINGS to use this feature. -+ -+ See doc/low-memory.rst for more discussion how to use this feature option -+ in practice. -diff --git a/dist/source/config/feature-options/DUK_OPT_FASTINT.yaml b/dist/source/config/feature-options/DUK_OPT_FASTINT.yaml -new file mode 100644 -index 0000000..704a8dd ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FASTINT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_FASTINT -+introduced: 1.2.0 -+tags: -+ - performance -+description: > -+ Enable support for 48-bit signed "fastint" integer values. Fastints are -+ transparent to user code (both C and ECMAScript) but may be faster than -+ IEEE doubles on some platforms, especially those using softints. The -+ downside of fastints is increased code footprint and a small performance -+ penalty for some kinds of code. -diff --git a/dist/source/config/feature-options/DUK_OPT_FORCE_ALIGN.yaml b/dist/source/config/feature-options/DUK_OPT_FORCE_ALIGN.yaml -new file mode 100644 -index 0000000..3682c47 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FORCE_ALIGN.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_FORCE_ALIGN -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Use -DDUK_OPT_FORCE_ALIGN=4 or -DDUK_OPT_FORCE_ALIGN=8 to force a -+ specific struct/value alignment instead of relying on Duktape's -+ automatic detection. This shouldn't normally be needed. -diff --git a/dist/source/config/feature-options/DUK_OPT_FORCE_BYTEORDER.yaml b/dist/source/config/feature-options/DUK_OPT_FORCE_BYTEORDER.yaml -new file mode 100644 -index 0000000..69e9dc0 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FORCE_BYTEORDER.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_FORCE_BYTEORDER -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Use this to skip byte order detection and force a specific byte order: -+ 1 for little endian, 2 for ARM "mixed" endian (integers little endian, -+ IEEE doubles mixed endian), 3 for big endian. Byte order detection -+ relies on unstandardized platform specific header files, so this may be -+ required for custom platforms if compilation fails in endianness detection. -diff --git a/dist/source/config/feature-options/DUK_OPT_FUNCPTR16.yaml b/dist/source/config/feature-options/DUK_OPT_FUNCPTR16.yaml -new file mode 100644 -index 0000000..aa592b1 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FUNCPTR16.yaml -@@ -0,0 +1,21 @@ -+define: DUK_OPT_FUNCPTR16 -+introduced: 1.1.0 -+related: -+ - DUK_OPT_FUNCPTR_ENC16 -+ - DUK_OPT_FUNCPTR_DEC16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable "compression" of arbitrary C function pointers into an unsigned 16-bit -+ value. Use together with DUK_OPT_FUNCPTR_ENC16 and DUK_OPT_FUNCPTR_DEC16. -+ -+ Pointers compressed are any C function pointers. Also NULL pointer must -+ encode and decode correctly. -+ -+ Currently it is required that NULL encodes to integer 0, and integer -+ 0 decodes to NULL. No other pointer can be encoded to 0. -+ -+ NOTE: This feature option is currently unimplemented, i.e. Duktape won't -+ compress any function pointers at the moment. It might not be necessary -+ to support a NULL function pointer (uncertain until taken into use). -diff --git a/dist/source/config/feature-options/DUK_OPT_FUNCPTR_DEC16.yaml b/dist/source/config/feature-options/DUK_OPT_FUNCPTR_DEC16.yaml -new file mode 100644 -index 0000000..f91bafd ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FUNCPTR_DEC16.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_FUNCPTR_DEC16 -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_FUNCPTR16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_OPT_FUNCPTR16 for function pointer compression. -+ DUK_OPT_FUNCPTR_DEC16(udata,x) is a macro with a userdata and duk_uint16_t -+ argument, and a void ptr return value. The userdata argument is the heap -+ userdata value given at heap creation. -diff --git a/dist/source/config/feature-options/DUK_OPT_FUNCPTR_ENC16.yaml b/dist/source/config/feature-options/DUK_OPT_FUNCPTR_ENC16.yaml -new file mode 100644 -index 0000000..2304e9e ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FUNCPTR_ENC16.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_FUNCPTR_ENC16 -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_FUNCPTR16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_OPT_FUNCPTR16 for function pointer compression. -+ DUK_OPT_FUNCPTR_ENC16(udata,p) is a macro with a userdata and void ptr -+ argument, and a duk_uint16_t return value. The userdata arguments is the -+ heap userdata value given at heap creation. -diff --git a/dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY.yaml b/dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY.yaml -new file mode 100644 -index 0000000..8444dac ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY -+tags: -+ - ecmascript -+description: > -+ Removed, use DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY.yaml b/dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY.yaml -new file mode 100644 -index 0000000..ba4d7dd ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY -+tags: -+ - ecmascript -+description: > -+ Removed, use DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_GC_TORTURE.yaml b/dist/source/config/feature-options/DUK_OPT_GC_TORTURE.yaml -new file mode 100644 -index 0000000..5298dd9 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_GC_TORTURE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_GC_TORTURE -+introduced: 1.0.0 -+tags: -+ - gc -+ - memory -+ - development -+description: > -+ Development time option: force full mark-and-sweep on every allocation to -+ stress test memory management. -diff --git a/dist/source/config/feature-options/DUK_OPT_HAVE_CUSTOM_H.yaml b/dist/source/config/feature-options/DUK_OPT_HAVE_CUSTOM_H.yaml -new file mode 100644 -index 0000000..1ae881d ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_HAVE_CUSTOM_H.yaml -@@ -0,0 +1,26 @@ -+define: DUK_OPT_HAVE_CUSTOM_H -+introduced: 1.0.0 -+deprecated: 1.3.0 -+tags: -+ - portability -+description: > -+ Normally you define DUK_OPT_xxx feature options and the autodetecting -+ duk_config.h (previously internal duk_features.h.in) header resolves -+ these with platform/compiler constraints to determine effective compilation -+ options for Duktape internals. The effective options are provided as -+ DUK_USE_xxx defines which you normally never see. -+ -+ If you define DUK_OPT_HAVE_CUSTOM_H, Duktape will include "duk_custom.h" -+ after determining the appropriate DUK_USE_xxx defines but before compiling -+ any code. The duk_custom.h header, which you provide, can then tweak the -+ active DUK_USE_xxx defines freely. See duk_config.h and genconfig option -+ metadata for the available defines. -+ -+ This approach is useful when the DUK_OPT_xxx feature options don't -+ provide enough flexibility to tweak the build. The downside is that you can -+ easily create inconsistent DUK_USE_xxx flags, the customization header -+ will be version specific, and you need to peek into Duktape internals to -+ know what defines to tweak. -+ -+ NOTE: This option is deprecated. The preferred method for customization -+ starting from Duktape 1.3.0 is to create/modify a "duk_config.h" header. -diff --git a/dist/source/config/feature-options/DUK_OPT_HEAPPTR16.yaml b/dist/source/config/feature-options/DUK_OPT_HEAPPTR16.yaml -new file mode 100644 -index 0000000..a93a181 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_HEAPPTR16.yaml -@@ -0,0 +1,34 @@ -+define: DUK_OPT_HEAPPTR16 -+introduced: 1.1.0 -+conflicts: -+ - DUK_OPT_DEBUG -+related: -+ - DUK_OPT_HEAPPTR_ENC16 -+ - DUK_OPT_HEAPPTR_DEC16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Enable "compression" of Duktape heap pointers into an unsigned 16-bit value. -+ Use together with DUK_OPT_HEAPPTR_ENC16 and DUK_OPT_HEAPPTR_DEC16. -+ -+ Pointers compressed are those allocated from Duktape heap, using the user -+ provided allocation functions. Also NULL pointer must encode and decode -+ correctly. -+ -+ Currently it is required that NULL encodes to integer 0, and integer -+ 0 decodes to NULL. No other pointer can be encoded to 0. -+ -+ This option reduces memory usage by several kilobytes, but has several -+ downsides. It can only be applied when Duktape heap is limited in size, -+ for instance, with 4-byte aligned allocations a 256kB heap (minus one value -+ for NULL) can be supported. Pointer encoding and decoding may be relatively -+ complicated as they need to correctly handle NULL pointers and -+ non-continuous memory maps used by some targets. The macro may need to call -+ out to a helper function in practice, which is much slower than an inline -+ implementation. -+ -+ Current limitation: Duktape internal debug code enabled with e.g. -+ DUK_OPT_DEBUG and DUK_OPT_DPRINT doesn't have enough plumbing to be able to -+ decode pointers. Debug printing cannot currently be enabled when pointer -+ compression is active. -diff --git a/dist/source/config/feature-options/DUK_OPT_HEAPPTR_DEC16.yaml b/dist/source/config/feature-options/DUK_OPT_HEAPPTR_DEC16.yaml -new file mode 100644 -index 0000000..9428827 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_HEAPPTR_DEC16.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_HEAPPTR_DEC16 -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_HEAPPTR16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_OPT_HEAPPTR16 for heap pointer compression. -+ DUK_OPT_HEAPPTR_DEC16(udata,x) is a macro with a userdata and duk_uint16_t -+ argument, and a void ptr return value. The userdata argument is the heap -+ userdata value given at heap creation. -diff --git a/dist/source/config/feature-options/DUK_OPT_HEAPPTR_ENC16.yaml b/dist/source/config/feature-options/DUK_OPT_HEAPPTR_ENC16.yaml -new file mode 100644 -index 0000000..ca64ca1 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_HEAPPTR_ENC16.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_HEAPPTR_ENC16 -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_HEAPPTR16 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use together with DUK_OPT_HEAPPTR16 for heap pointer compression. -+ DUK_OPT_HEAPPTR_ENC16(udata,p) is a macro with a userdata and void ptr -+ argument, and a duk_uint16_t return value. The userdata argument is the -+ heap userdata value given at heap creation. -diff --git a/dist/source/config/feature-options/DUK_OPT_INTERRUPT_COUNTER.yaml b/dist/source/config/feature-options/DUK_OPT_INTERRUPT_COUNTER.yaml -new file mode 100644 -index 0000000..835af64 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_INTERRUPT_COUNTER.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_INTERRUPT_COUNTER -+introduced: 1.1.0 -+related: -+ - DUK_OPT_DEBUGGER_SUPPORT -+tags: -+ - execution -+ - debugger -+description: > -+ Enable the internal bytecode executor periodic interrupt counter. -+ The mechanism is used to implement e.g. execution step limit, custom -+ profiling, and debugger interaction. Enabling the interrupt counter -+ has a small impact on execution performance. -diff --git a/dist/source/config/feature-options/DUK_OPT_JSON_STRINGIFY_FASTPATH.yaml b/dist/source/config/feature-options/DUK_OPT_JSON_STRINGIFY_FASTPATH.yaml -new file mode 100644 -index 0000000..6d6431c ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_JSON_STRINGIFY_FASTPATH.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_JSON_STRINGIFY_FASTPATH -+introduced: 1.3.0 -+tags: -+ - performance -+ - fastpath -+ - lowmemory -+description: > -+ Enable fast apth for JSON.stringify() serialization. See -+ DUK_USE_JSON_STRINGIFY_FASTPATH for details. -diff --git a/dist/source/config/feature-options/DUK_OPT_LIGHTFUNC_BUILTINS.yaml b/dist/source/config/feature-options/DUK_OPT_LIGHTFUNC_BUILTINS.yaml -new file mode 100644 -index 0000000..c28a0e6 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_LIGHTFUNC_BUILTINS.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_LIGHTFUNC_BUILTINS -+introduced: 1.1.0 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Force built-in functions to be lightweight functions. This reduces -+ memory footprint by around 14 kB at the cost of some non-compliant -+ behavior. -diff --git a/dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY.yaml b/dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY.yaml -new file mode 100644 -index 0000000..4220071 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY.yaml -@@ -0,0 +1,14 @@ -+define: DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Add a non-standard "caller" property to non-strict function instances -+ for better compatibility with existing code. The semantics of this -+ property are not standardized and may vary between engines; Duktape tries -+ to behave close to V8 and Spidermonkey. See -+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller -+ description of the property. This feature disables tail call support. -+ -+ This feature conflicts with several other features, so you should use it -+ only if it's absolutely necessary. -diff --git a/dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY.yaml b/dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY.yaml -new file mode 100644 -index 0000000..e9abe9f ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Add a non-standard "source" property to function instances. This allows -+ function toString() to print out the actual function source. The property -+ is disabled by default because it increases memory footprint. -+ -+ NOTE: Unimplemented as of Duktape 1.2.0. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT.yaml -new file mode 100644 -index 0000000..9f771e8 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT -+tags: -+ - ecmascript -+description: > -+ Removed, use DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_AUGMENT_ERRORS.yaml b/dist/source/config/feature-options/DUK_OPT_NO_AUGMENT_ERRORS.yaml -new file mode 100644 -index 0000000..9faffd8 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_AUGMENT_ERRORS.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_NO_AUGMENT_ERRORS -+introduced: 1.0.0 -+related: -+ - DUK_OPT_NO_TRACEBACKS -+tags: -+ - ecmascript -+description: > -+ Don't augment ECMAScript error objects with custom fields like fileName, -+ lineNumber, and traceback data. Also disables Duktape.errCreate and -+ Duktape.errThrow error handler callbacks. Implies DUK_OPT_NO_TRACEBACKS. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_BROWSER_LIKE.yaml b/dist/source/config/feature-options/DUK_OPT_NO_BROWSER_LIKE.yaml -new file mode 100644 -index 0000000..002861e ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_BROWSER_LIKE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_BROWSER_LIKE -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable browser-like functions. Makes print() and alert() throw an error. -+ -+ This option is confusing when used with the Duktape command line tool, as -+ the command like tool will immediately panic on startup. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_BUFFEROBJECT_SUPPORT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_BUFFEROBJECT_SUPPORT.yaml -new file mode 100644 -index 0000000..395aaf5 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_BUFFEROBJECT_SUPPORT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_BUFFEROBJECT_SUPPORT -+introduced: 1.3.0 -+tags: -+ - ecmascript6 -+description: > -+ Disable support for Khronos/ES6 typed arrays and Node.js Buffer objects -+ which reduces code footprint. When disabled, Duktape custom plain buffers -+ and Duktape.Buffer are still supported. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_BYTECODE_DUMP_SUPPORT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_BYTECODE_DUMP_SUPPORT.yaml -new file mode 100644 -index 0000000..26c5117 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_BYTECODE_DUMP_SUPPORT.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_NO_BYTECODE_DUMP_SUPPORT -+introduced: 1.3.0 -+tags: -+ - api -+description: > -+ Disable API calls to dump/load functions to bytecode (reduces code -+ footprint). -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_COMMONJS_MODULES.yaml b/dist/source/config/feature-options/DUK_OPT_NO_COMMONJS_MODULES.yaml -new file mode 100644 -index 0000000..61e8273 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_COMMONJS_MODULES.yaml -@@ -0,0 +1,6 @@ -+define: DUK_OPT_NO_COMMONJS_MODULES -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable support for CommonJS modules. Causes require() to throw an error. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY.yaml b/dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY.yaml -new file mode 100644 -index 0000000..e89fbdd ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY -+introduced: 1.0.0 -+tags: -+ - ecmascript -+ - ecmascript6 -+description: > -+ Disable the non-standard (ES6) Object.prototype.__proto__ property -+ which is enabled by default. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF.yaml b/dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF.yaml -new file mode 100644 -index 0000000..e1f3cc4 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF -+introduced: 1.0.0 -+tags: -+ - ecmascript -+ - ecmascript6 -+description: > -+ Disable the non-standard (ES6) Object.setPrototypeOf method which -+ is enabled by default. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_ES6_PROXY.yaml b/dist/source/config/feature-options/DUK_OPT_NO_ES6_PROXY.yaml -new file mode 100644 -index 0000000..dcddbd2 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_ES6_PROXY.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_ES6_PROXY -+introduced: 1.0.0 -+tags: -+ - ecmascript -+ - ecmascript6 -+description: > -+ Disable the non-standard (ES6) Proxy object which is enabled by -+ default. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_FILE_IO.yaml b/dist/source/config/feature-options/DUK_OPT_NO_FILE_IO.yaml -new file mode 100644 -index 0000000..52646a5 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_FILE_IO.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_NO_FILE_IO -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Disable use of ANSI C file I/O which might be a portability issue on some -+ platforms. Causes duk_eval_file() to throw an error, makes built-in -+ print() and alert() no-ops, and suppresses writing of a panic -+ message to stderr on panic. This option does not suppress debug -+ printing so don't enable debug printing if you wish to avoid I/O. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_FUNC_STMT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_FUNC_STMT.yaml -new file mode 100644 -index 0000000..5a309a6 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_FUNC_STMT.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_FUNC_STMT -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NO_NONSTD_FUNC_STMT -+tags: -+ - ecmascript -+description: > -+ Removed, use DUK_OPT_NO_NONSTD_FUNC_STMT instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_JC.yaml b/dist/source/config/feature-options/DUK_OPT_NO_JC.yaml -new file mode 100644 -index 0000000..ba7d86f ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_JC.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_NO_JC -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable support for the JC format. Reduces code footprint. An attempt -+ to encode or decode the format causes an error. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_JSONC.yaml b/dist/source/config/feature-options/DUK_OPT_NO_JSONC.yaml -new file mode 100644 -index 0000000..8c4e0e7 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_JSONC.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_JSONC -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NO_JC -+tags: -+ - ecmascript -+description: > -+ Removed, use DUK_OPT_NO_JC instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_JSONX.yaml b/dist/source/config/feature-options/DUK_OPT_NO_JSONX.yaml -new file mode 100644 -index 0000000..d141a27 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_JSONX.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_JSONX -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NO_JX -+tags: -+ - ecmascript -+description: > -+ Removed, use DUK_OPT_NO_JX instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_JX.yaml b/dist/source/config/feature-options/DUK_OPT_NO_JX.yaml -new file mode 100644 -index 0000000..be22edd ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_JX.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_NO_JX -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable support for the JX format. Reduces code footprint. An attempt -+ to encode or decode the format causes an error. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_MARK_AND_SWEEP.yaml b/dist/source/config/feature-options/DUK_OPT_NO_MARK_AND_SWEEP.yaml -new file mode 100644 -index 0000000..3283488 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_MARK_AND_SWEEP.yaml -@@ -0,0 +1,14 @@ -+define: DUK_OPT_NO_MARK_AND_SWEEP -+introduced: 1.0.0 -+tags: -+ - gc -+ - memory -+description: > -+ Disable mark-and-sweep and use only reference counting for garbage -+ collection. This reduces code footprint and eliminates garbage collection -+ pauses, but objects participating in unreachable reference cycles won't be -+ collected until the Duktape heap is destroyed. In particular, function -+ instances won't be collected because they're always in a reference cycle -+ with their default prototype object. Unreachable objects are collected if -+ you break reference cycles manually (and are always freed when a heap is -+ destroyed). -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_MS_STRINGTABLE_RESIZE.yaml b/dist/source/config/feature-options/DUK_OPT_NO_MS_STRINGTABLE_RESIZE.yaml -new file mode 100644 -index 0000000..9b0e6af ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_MS_STRINGTABLE_RESIZE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_MS_STRINGTABLE_RESIZE -+introduced: 1.0.0 -+tags: -+ - gc -+ - memory -+description: > -+ Disable forced string intern table resize during mark-and-sweep garbage -+ collection. This may be useful when reference counting is disabled, as -+ mark-and-sweep collections will be more frequent and thus more expensive. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT.yaml -new file mode 100644 -index 0000000..df5ecda ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Don't give setter/getter calls the property name being accessed as -+ an additional, non-standard property. See -+ http://duktape.org/guide.html#propertyvirtualization. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER.yaml b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER.yaml -new file mode 100644 -index 0000000..eb7f322 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ For better compatibility with existing code, Array.prototype.concat() has -+ non-standard behavior by default for trailing non-existent elements of -+ the concat result, see -+ https://github.com/svaarala/duktape/blob/master/ecmascript-testcases/test-bi-array-proto-concat-nonstd-trailing.js. -+ -+ If this option is given, concat() will behave in a strictly conforming -+ fashion, ignoring non-existent trailing elements in the result length. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER.yaml b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER.yaml -new file mode 100644 -index 0000000..a43a81c ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER.yaml -@@ -0,0 +1,12 @@ -+define: DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ For better compatibility with existing code, Array.prototype.map() has -+ non-standard behavior by default for trailing non-existent elements of -+ the map result, see -+ https://github.com/svaarala/duktape/blob/master/ecmascript-testcases/test-bi-array-proto-map-nonstd-trailing.js. -+ -+ If this option is given, map() will behave in a strictly conforming -+ fashion, ignoring non-existent trailing elements in the result length. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml -new file mode 100644 -index 0000000..308d720 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT.yaml -@@ -0,0 +1,13 @@ -+define: DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ For better compatibility with existing code, Array.prototype.splice() has -+ non-standard behavior by default when the second argument (deleteCount) -+ is not given: the splice operation is extended to the end of the array, see -+ https://github.com/svaarala/duktape/blob/master/ecmascript-testcases/test-bi-array-proto-splice-no-delcount.js. -+ -+ If this option is given, splice() will behave in a strictly conforming -+ fashion, treating a missing deleteCount the same as an undefined (or 0) -+ value. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_FUNC_STMT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_FUNC_STMT.yaml -new file mode 100644 -index 0000000..b27b4fc ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_FUNC_STMT.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_NO_NONSTD_FUNC_STMT -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable support for function declarations outside program or function top -+ level (also known as "function statements"). Such declarations are -+ non-standard and the strictly compliant behavior is to treat them as a -+ SyntaxError. Default behavior is to treat them like ordinary function -+ declarations ("hoist" them to function top) with V8-like semantics. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029.yaml b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029.yaml -new file mode 100644 -index 0000000..b1d87e4 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029 -+introduced: 1.1.0 -+tags: -+ - ecmascript -+description: > -+ By default Duktape JSON.stringify() will escape U+2028 and U+2029 which -+ is non-compliant behavior. This is the default to make JSON.stringify() -+ output valid when embedded in a web page or parsed with eval(). This -+ feature option enables the compliant behavior, i.e. no escaping for U+2028 -+ and U+2029. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT.yaml -new file mode 100644 -index 0000000..ed5bfbd ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT -+introduced: 1.2.0 -+tags: -+ - ecmascript -+description: > -+ By default Duktape String.fromCharCode() allows 32-bit codepoints which is -+ non-compliant (the E5.1 specification has a ToUint16() coercion for the -+ codepoints) but useful because Duktape supports non-BMP strings. This -+ feature option restores the compliant behavior. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY.yaml b/dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY.yaml -new file mode 100644 -index 0000000..c25ce8a ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_NO_OBJECT_ES6_PROTO_PROPERTY -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY -+tags: -+ - ecmascript -+ - ecmascript6 -+description: > -+ Removed, use DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF.yaml b/dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF.yaml -new file mode 100644 -index 0000000..f2b930e ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_NO_OBJECT_ES6_SETPROTOTYPEOF -+introduced: 1.0.0 -+removed: 1.0.0 -+related: -+ - DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF -+tags: -+ - ecmascript -+ - ecmascript6 -+description: > -+ Removed, use DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF instead. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_OCTAL_SUPPORT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_OCTAL_SUPPORT.yaml -new file mode 100644 -index 0000000..482d9cc ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_OCTAL_SUPPORT.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_NO_OCTAL_SUPPORT -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable optional octal number support (ECMAScript E5/E5.1 -+ Annex B: http://www.ecma-international.org/ecma-262/5.1/#sec-B). -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_PACKED_TVAL.yaml b/dist/source/config/feature-options/DUK_OPT_NO_PACKED_TVAL.yaml -new file mode 100644 -index 0000000..a00e468 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_PACKED_TVAL.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_PACKED_TVAL -+introduced: 1.0.0 -+tags: -+ - memory -+ - portability -+description: > -+ Don't use the packed 8-byte internal value representation even if otherwise -+ possible. The packed representation has more platform/compiler portability -+ issues than the unpacked one. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_PC2LINE.yaml b/dist/source/config/feature-options/DUK_OPT_NO_PC2LINE.yaml -new file mode 100644 -index 0000000..dd46056 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_PC2LINE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_PC2LINE -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Don't record a "pc2line" map into function instances. Without this map, -+ exceptions won't have meaningful line numbers (virtual machine program -+ counter values cannot be translated to line numbers) but function instances -+ will have a smaller footprint. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_REFERENCE_COUNTING.yaml b/dist/source/config/feature-options/DUK_OPT_NO_REFERENCE_COUNTING.yaml -new file mode 100644 -index 0000000..df1a218 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_REFERENCE_COUNTING.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_REFERENCE_COUNTING -+introduced: 1.0.0 -+tags: -+ - gc -+ - memory -+description: > -+ Disable reference counting and use only mark-and-sweep for garbage -+ collection. Although this reduces memory footprint of heap objects, the -+ downside is much more fluctuation in memory usage. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_REGEXP_SUPPORT.yaml b/dist/source/config/feature-options/DUK_OPT_NO_REGEXP_SUPPORT.yaml -new file mode 100644 -index 0000000..fe20fa1 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_REGEXP_SUPPORT.yaml -@@ -0,0 +1,11 @@ -+define: DUK_OPT_NO_REGEXP_SUPPORT -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable support for regular expressions. Regexp literals are treated as -+ a SyntaxError, RegExp constructor and prototype functions throw an error, -+ String.prototype.replace() throws an error if given a regexp search value, -+ String.prototype.split() throws an error if given a regexp separator value, -+ String.prototype.search() and String.prototype.match() throw an error -+ unconditionally. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_SECTION_B.yaml b/dist/source/config/feature-options/DUK_OPT_NO_SECTION_B.yaml -new file mode 100644 -index 0000000..683ad73 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_SECTION_B.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_NO_SECTION_B -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable optional features in ECMAScript specification -+ Annex B: http://www.ecma-international.org/ecma-262/5.1/#sec-B. -+ Causes escape(), unescape(), and String.prototype.substr() to throw -+ an error. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_SOURCE_NONBMP.yaml b/dist/source/config/feature-options/DUK_OPT_NO_SOURCE_NONBMP.yaml -new file mode 100644 -index 0000000..0ddfad3 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_SOURCE_NONBMP.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_NO_SOURCE_NONBMP -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Disable accurate Unicode support for non-BMP characters in source code. -+ Non-BMP characters are then always accepted as identifier characters. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_STRICT_DECL.yaml b/dist/source/config/feature-options/DUK_OPT_NO_STRICT_DECL.yaml -new file mode 100644 -index 0000000..e383290 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_STRICT_DECL.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_STRICT_DECL -+introduced: 1.1.0 -+tags: -+ - ecmascript -+ - experimental -+description: > -+ Disable support for "use strict" declaration so that ECMAScript code is -+ always executed in non-strict mode. Duktape/C functions remain strict. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_TRACEBACKS.yaml b/dist/source/config/feature-options/DUK_OPT_NO_TRACEBACKS.yaml -new file mode 100644 -index 0000000..5f4d2c1 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_TRACEBACKS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_TRACEBACKS -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Don't record traceback data into ECMAScript error objects (but still record -+ fileName and lineNumber). Reduces footprint and makes error handling a bit -+ faster, at the cost of less informative ECMAScript errors. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_VERBOSE_ERRORS.yaml b/dist/source/config/feature-options/DUK_OPT_NO_VERBOSE_ERRORS.yaml -new file mode 100644 -index 0000000..cadabc6 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_VERBOSE_ERRORS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_VERBOSE_ERRORS -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Don't provide error message strings or filename/line information for errors -+ generated by Duktape. Reduces footprint, at the cost of much less -+ informative ECMAScript errors. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_VOLUNTARY_GC.yaml b/dist/source/config/feature-options/DUK_OPT_NO_VOLUNTARY_GC.yaml -new file mode 100644 -index 0000000..ff2f0c0 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_VOLUNTARY_GC.yaml -@@ -0,0 +1,13 @@ -+define: DUK_OPT_NO_VOLUNTARY_GC -+introduced: 1.0.0 -+tags: -+ - gc -+ - memory -+description: > -+ Disable voluntary periodic mark-and-sweep collection. A mark-and-sweep -+ collection is still triggered in an out-of-memory condition. This option -+ should usually be combined with reference counting, which collects all -+ non-cyclical garbage. Application code should also request an explicit -+ garbage collection from time to time when appropriate. When this option -+ is used, Duktape will have no garbage collection pauses in ordinary use, -+ which is useful for timing sensitive applications like games. -diff --git a/dist/source/config/feature-options/DUK_OPT_NO_ZERO_BUFFER_DATA.yaml b/dist/source/config/feature-options/DUK_OPT_NO_ZERO_BUFFER_DATA.yaml -new file mode 100644 -index 0000000..4696d49 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_NO_ZERO_BUFFER_DATA.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_NO_ZERO_BUFFER_DATA -+introduced: 1.0.0 -+tags: -+ - memory -+ - ecmascript -+description: > -+ By default Duktape zeroes data allocated for buffer values. Define -+ this to disable the zeroing (perhaps for performance reasons). -diff --git a/dist/source/config/feature-options/DUK_OPT_OBJSIZES16.yaml b/dist/source/config/feature-options/DUK_OPT_OBJSIZES16.yaml -new file mode 100644 -index 0000000..c0bd3da ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_OBJSIZES16.yaml -@@ -0,0 +1,11 @@ -+define: DUK_OPT_OBJSIZES16 -+introduced: 1.1.0 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit object entry and array part sizes (for low memory -+ environments). Also automatically drops support for an object hash part -+ to further reduce memory usage; there are rarely large objects in low -+ memory environments simply because there's no memory to store a lot of -+ properties. -diff --git a/dist/source/config/feature-options/DUK_OPT_PANIC_HANDLER.yaml b/dist/source/config/feature-options/DUK_OPT_PANIC_HANDLER.yaml -new file mode 100644 -index 0000000..543061a ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_PANIC_HANDLER.yaml -@@ -0,0 +1,6 @@ -+define: DUK_OPT_PANIC_HANDLER -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Provide a custom panic handler. -diff --git a/dist/source/config/feature-options/DUK_OPT_REFCOUNT16.yaml b/dist/source/config/feature-options/DUK_OPT_REFCOUNT16.yaml -new file mode 100644 -index 0000000..3e824df ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_REFCOUNT16.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_REFCOUNT16 -+introduced: 1.1.0 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit reference count field (for low memory environments). -diff --git a/dist/source/config/feature-options/DUK_OPT_SEGFAULT_ON_PANIC.yaml b/dist/source/config/feature-options/DUK_OPT_SEGFAULT_ON_PANIC.yaml -new file mode 100644 -index 0000000..bc2288c ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_SEGFAULT_ON_PANIC.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_SEGFAULT_ON_PANIC -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Cause the default panic handler to cause a segfault instead of using -+ abort() or exit(). This is useful when debugging with valgrind, -+ as a segfault provides a nice C traceback in valgrind. -diff --git a/dist/source/config/feature-options/DUK_OPT_SELF_TESTS.yaml b/dist/source/config/feature-options/DUK_OPT_SELF_TESTS.yaml -new file mode 100644 -index 0000000..e59c9d5 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_SELF_TESTS.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_SELF_TESTS -+introduced: 1.0.0 -+tags: -+ - debug -+description: > -+ Perform run-time self tests when a Duktape heap is created. Catches -+ platform/compiler problems which cannot be reliably detected during -+ compile time. Not enabled by default because of the extra footprint. -diff --git a/dist/source/config/feature-options/DUK_OPT_SETJMP.yaml b/dist/source/config/feature-options/DUK_OPT_SETJMP.yaml -new file mode 100644 -index 0000000..ff00d5b ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_SETJMP.yaml -@@ -0,0 +1,18 @@ -+define: DUK_OPT_SETJMP -+introduced: 1.1.0 -+removed: 1.5.0 -+tags: -+ - portability -+description: > -+ Force setjmp/longjmp for long control transfers. -+ -+ The default long control transfer provider is setjmp/longjmp because it -+ is the most portable option. When a better provider is known for a platform, -+ Duktape may default to that (e.g. _setjmp/_longjmp is the default for -+ macOS/iOS, see GH-55). With this feature option you can force Duktape to -+ explicitly use setjmp/longjmp even in these cases. -+ -+ The downside of setjmp/longjmp is that signal mask saving behavior is not -+ specified and varies between platforms. Signal mask saving may have a -+ significant performance impact so you may want to force a specific provider -+ if performance matters for your application. -diff --git a/dist/source/config/feature-options/DUK_OPT_SHUFFLE_TORTURE.yaml b/dist/source/config/feature-options/DUK_OPT_SHUFFLE_TORTURE.yaml -new file mode 100644 -index 0000000..fb2a5c3 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_SHUFFLE_TORTURE.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_SHUFFLE_TORTURE -+introduced: 1.2.0 -+tags: -+ - gc -+ - memory -+ - development -+description: > -+ Development time option: force compiler to shuffle every possible opcode -+ to stress shuffle behavior which is otherwise difficult to test for -+ comprehensively. -diff --git a/dist/source/config/feature-options/DUK_OPT_SIGSETJMP.yaml b/dist/source/config/feature-options/DUK_OPT_SIGSETJMP.yaml -new file mode 100644 -index 0000000..fdaede2 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_SIGSETJMP.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_SIGSETJMP -+introduced: 1.1.0 -+removed: 1.5.0 -+tags: -+ - portability -+description: > -+ Force sigsetjmp/siglongjmp with savesigs == 0 for long control -+ transfers (i.e. signal mask not saved/restored). See comments in -+ DUK_OPT_SETJMP. -diff --git a/dist/source/config/feature-options/DUK_OPT_STRHASH16.yaml b/dist/source/config/feature-options/DUK_OPT_STRHASH16.yaml -new file mode 100644 -index 0000000..2adeeef ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_STRHASH16.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_STRHASH16 -+introduced: 1.1.0 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit string hash field (for low memory environments). -diff --git a/dist/source/config/feature-options/DUK_OPT_STRICT_UTF8_SOURCE.yaml b/dist/source/config/feature-options/DUK_OPT_STRICT_UTF8_SOURCE.yaml -new file mode 100644 -index 0000000..2d602fa ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_STRICT_UTF8_SOURCE.yaml -@@ -0,0 +1,9 @@ -+define: DUK_OPT_STRICT_UTF8_SOURCE -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Enable strict UTF-8 parsing of source code. When enabled, non-shortest -+ encodings (normally invalid UTF-8) and surrogate pair codepoints are -+ accepted as valid source code characters. This option breaks compatibility -+ with some test262 tests. -diff --git a/dist/source/config/feature-options/DUK_OPT_STRLEN16.yaml b/dist/source/config/feature-options/DUK_OPT_STRLEN16.yaml -new file mode 100644 -index 0000000..848aa52 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_STRLEN16.yaml -@@ -0,0 +1,7 @@ -+define: DUK_OPT_STRLEN16 -+introduced: 1.1.0 -+tags: -+ - lowmemory -+ - experimental -+description: > -+ Use a 16-bit string length field (for low memory environments). -diff --git a/dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN.yaml b/dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN.yaml -new file mode 100644 -index 0000000..cefb795 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN.yaml -@@ -0,0 +1,25 @@ -+define: DUK_OPT_STRTAB_CHAIN -+introduced: 1.1.0 -+related: -+ - DUK_OPT_STRTAB_CHAIN_SIZE -+tags: -+ - lowmemory -+description: > -+ Replace the default (open addressing, probing) string table structure with -+ one based on separate chaining. There is a fixed-size top level hash table -+ (whose size is defined using DUK_OPT_STRTAB_CHAIN_SIZE), with each entry in -+ the hash table being: (a) NULL, (b) a duk_hstring pointer, or (c) a pointer -+ to an array of duk_hstring pointers. The pointer arrays are gappy (the gaps -+ are reused on new inserts) and are never shrunk at the moment. -+ -+ This option is intended for low memory environments to make Duktape's memory -+ behavior match a typical pool-based allocator better as follows: -+ -+ The top level fixed structure never changes size, so there is no hash table -+ resize, and thus no need for resize temporaries. The default string table -+ algorithm needs resizing from time to time and doesn't resize in place, so -+ you effectively need twice the string table size temporarily during a resize. -+ -+ The pointer arrays vary in size, but their size (typically 8 to 64 bytes, -+ depending on the load factor) matches that of many other allocations which -+ works well with a pooled allocator. -diff --git a/dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN_SIZE.yaml b/dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN_SIZE.yaml -new file mode 100644 -index 0000000..4137a7c ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_STRTAB_CHAIN_SIZE.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_STRTAB_CHAIN_SIZE -+introduced: 1.1.0 -+requires: -+ - DUK_OPT_STRTAB_CHAIN -+tags: -+ - lowmemory -+description: > -+ Define stringtable size for DUK_OPT_STRTAB_CHAIN. -diff --git a/dist/source/config/feature-options/DUK_OPT_TARGET_INFO.yaml b/dist/source/config/feature-options/DUK_OPT_TARGET_INFO.yaml -new file mode 100644 -index 0000000..59d550c ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_TARGET_INFO.yaml -@@ -0,0 +1,8 @@ -+define: DUK_OPT_TARGET_INFO -+introduced: 1.2.0 -+tags: -+ - debugger -+description: > -+ Define a freeform human readable string to describe the target device (e.g. -+ "Arduino Yun"). This string will be sent as part of version/target info in -+ the debugger protocol and shows up in the debugger UI. -diff --git a/dist/source/config/feature-options/DUK_OPT_TRACEBACK_DEPTH.yaml b/dist/source/config/feature-options/DUK_OPT_TRACEBACK_DEPTH.yaml -new file mode 100644 -index 0000000..88e73b8 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_TRACEBACK_DEPTH.yaml -@@ -0,0 +1,6 @@ -+define: DUK_OPT_TRACEBACK_DEPTH -+introduced: 1.0.0 -+tags: -+ - ecmascript -+description: > -+ Override default traceback collection depth. The default is currently 10. -diff --git a/dist/source/config/feature-options/DUK_OPT_UNDERSCORE_SETJMP.yaml b/dist/source/config/feature-options/DUK_OPT_UNDERSCORE_SETJMP.yaml -new file mode 100644 -index 0000000..eeaf0ca ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_UNDERSCORE_SETJMP.yaml -@@ -0,0 +1,10 @@ -+define: DUK_OPT_UNDERSCORE_SETJMP -+introduced: 1.1.0 -+removed: 1.5.0 -+tags: -+ - portability -+description: > -+ Force _setjmp/_longjmp for long control transfers. This ensures signal -+ mask is not saved which can be a lot faster if setjmp/longjmp saves the -+ signal mask (this varies between platforms). See comments in -+ DUK_OPT_SETJMP. -diff --git a/dist/source/config/feature-options/DUK_OPT_USER_INITJS.yaml b/dist/source/config/feature-options/DUK_OPT_USER_INITJS.yaml -new file mode 100644 -index 0000000..af03442 ---- /dev/null -+++ b/dist/source/config/feature-options/DUK_OPT_USER_INITJS.yaml -@@ -0,0 +1,11 @@ -+define: DUK_OPT_USER_INITJS -+introduced: 1.0.0 -+tags: -+ - portability -+description: > -+ Provide a string to evaluate when a thread with new built-ins (a new global -+ environment) is created. This allows you to make minor modifications to the -+ global environment before any code is executed in it. The value must be a -+ string, e.g.:: -DDUK_OPT_USER_INITJS='"this.foo = 123"'. -+ -+ Errors in the initialization code result in a fatal error. -diff --git a/dist/source/config/header-snippets/64bitops.h.in b/dist/source/config/header-snippets/64bitops.h.in -new file mode 100644 -index 0000000..2dbbf11 ---- /dev/null -+++ b/dist/source/config/header-snippets/64bitops.h.in -@@ -0,0 +1,11 @@ -+/* Check whether we should use 64-bit integers or not. -+ * -+ * Quite incomplete now. Use 64-bit types if detected (C99 or other detection) -+ * unless they are known to be unreliable. For instance, 64-bit types are -+ * available on VBCC but seem to misbehave. -+ */ -+#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC) -+#define DUK_USE_64BIT_OPS -+#else -+#undef DUK_USE_64BIT_OPS -+#endif -diff --git a/dist/source/config/header-snippets/alignment_fillin.h.in b/dist/source/config/header-snippets/alignment_fillin.h.in -new file mode 100644 -index 0000000..680f335 ---- /dev/null -+++ b/dist/source/config/header-snippets/alignment_fillin.h.in -@@ -0,0 +1,26 @@ -+/* -+ * Alignment requirement and support for unaligned accesses -+ * -+ * Assume unaligned accesses are not supported unless specifically allowed -+ * in the target platform. Some platforms may support unaligned accesses -+ * but alignment to 4 or 8 may still be desirable. Note that unaligned -+ * accesses (and even pointers) relative to natural alignment (regardless -+ * of target alignment) are technically undefined behavior and thus -+ * compiler/architecture specific. -+ */ -+ -+/* If not forced, use safe default for alignment. */ -+#if !defined(DUK_USE_ALIGN_BY) -+#define DUK_USE_ALIGN_BY 8 -+#endif -+ -+/* Compiler specific hackery needed to force struct size to match alignment, -+ * see e.g. duk_hbuffer.h. -+ * -+ * http://stackoverflow.com/questions/11130109/c-struct-size-alignment -+ * http://stackoverflow.com/questions/10951039/specifying-64-bit-alignment -+ */ -+#if !(defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_GCC_ATTR) || \ -+ defined(DUK_USE_PACK_CLANG_ATTR) || defined(DUK_USE_PACK_DUMMY_MEMBER)) -+#define DUK_USE_PACK_DUMMY_MEMBER -+#endif -diff --git a/dist/source/config/header-snippets/architecture_fillins.h.in b/dist/source/config/header-snippets/architecture_fillins.h.in -new file mode 100644 -index 0000000..e69de29 -diff --git a/dist/source/config/header-snippets/byteorder_derived.h.in b/dist/source/config/header-snippets/byteorder_derived.h.in -new file mode 100644 -index 0000000..5284b47 ---- /dev/null -+++ b/dist/source/config/header-snippets/byteorder_derived.h.in -@@ -0,0 +1,21 @@ -+/* -+ * Convert DUK_USE_BYTEORDER, from whatever source, into currently used -+ * internal defines. If detection failed, #error out. -+ */ -+ -+#if defined(DUK_USE_BYTEORDER) -+#if (DUK_USE_BYTEORDER == 1) -+#define DUK_USE_INTEGER_LE -+#define DUK_USE_DOUBLE_LE -+#elif (DUK_USE_BYTEORDER == 2) -+#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */ -+#define DUK_USE_DOUBLE_ME -+#elif (DUK_USE_BYTEORDER == 3) -+#define DUK_USE_INTEGER_BE -+#define DUK_USE_DOUBLE_BE -+#else -+#error unsupported: byte order invalid -+#endif /* byte order */ -+#else -+#error unsupported: byte order detection failed -+#endif /* defined(DUK_USE_BYTEORDER) */ -diff --git a/dist/source/config/header-snippets/byteorder_fillin.h.in b/dist/source/config/header-snippets/byteorder_fillin.h.in -new file mode 100644 -index 0000000..4432126 ---- /dev/null -+++ b/dist/source/config/header-snippets/byteorder_fillin.h.in -@@ -0,0 +1,109 @@ -+/* -+ * Byte order and double memory layout detection -+ * -+ * Endianness detection is a major portability hassle because the macros -+ * and headers are not standardized. There's even variance across UNIX -+ * platforms. Even with "standard" headers, details like underscore count -+ * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used -+ * (Crossbridge has a single underscore, for instance). -+ * -+ * The checks below are structured with this in mind: several approaches are -+ * used, and at the end we check if any of them worked. This allows generic -+ * approaches to be tried first, and platform/compiler specific hacks tried -+ * last. As a last resort, the user can force a specific endianness, as it's -+ * not likely that automatic detection will work on the most exotic platforms. -+ * -+ * Duktape supports little and big endian machines. There's also support -+ * for a hybrid used by some ARM machines where integers are little endian -+ * but IEEE double values use a mixed order (12345678 -> 43218765). This -+ * byte order for doubles is referred to as "mixed endian". -+ */ -+ -+/* GCC and Clang provide endianness defines as built-in predefines, with -+ * leading and trailing double underscores (e.g. __BYTE_ORDER__). See -+ * output of "make gccpredefs" and "make clangpredefs". Clang doesn't -+ * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang. -+ * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html -+ */ -+#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) -+#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -+#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) -+#define DUK_USE_BYTEORDER 1 -+#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -+#define DUK_USE_BYTEORDER 2 -+#elif !defined(__FLOAT_WORD_ORDER__) -+/* Float word order not known, assume not a hybrid. */ -+#define DUK_USE_BYTEORDER 1 -+#else -+/* Byte order is little endian but cannot determine IEEE double word order. */ -+#endif /* float word order */ -+#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -+#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) -+#define DUK_USE_BYTEORDER 3 -+#elif !defined(__FLOAT_WORD_ORDER__) -+/* Float word order not known, assume not a hybrid. */ -+#define DUK_USE_BYTEORDER 3 -+#else -+/* Byte order is big endian but cannot determine IEEE double word order. */ -+#endif /* float word order */ -+#else -+/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit -+ * integer ordering and is not relevant. -+ */ -+#endif /* integer byte order */ -+#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */ -+ -+/* More or less standard endianness predefines provided by header files. -+ * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER -+ * will be big endian, see: http://lists.mysql.com/internals/443. -+ * On some platforms some defines may be present with an empty value which -+ * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453. -+ */ -+#if !defined(DUK_USE_BYTEORDER) -+#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \ -+ defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \ -+ defined(__LITTLE_ENDIAN__) -+#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \ -+ defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN) -+#define DUK_USE_BYTEORDER 1 -+#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ -+ defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -+#define DUK_USE_BYTEORDER 2 -+#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -+/* Float word order not known, assume not a hybrid. */ -+#define DUK_USE_BYTEORDER 1 -+#else -+/* Byte order is little endian but cannot determine IEEE double word order. */ -+#endif /* float word order */ -+#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \ -+ defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \ -+ defined(__BIG_ENDIAN__) -+#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \ -+ defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN) -+#define DUK_USE_BYTEORDER 3 -+#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER) -+/* Float word order not known, assume not a hybrid. */ -+#define DUK_USE_BYTEORDER 3 -+#else -+/* Byte order is big endian but cannot determine IEEE double word order. */ -+#endif /* float word order */ -+#else -+/* Cannot determine byte order. */ -+#endif /* integer byte order */ -+#endif /* !defined(DUK_USE_BYTEORDER) */ -+ -+/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__: -+ * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - > 56U) | \ -+ ((((duk_uint64_t) (x)) >> 40U) & DUK_U64_CONSTANT(0xff00)) | \ -+ ((((duk_uint64_t) (x)) >> 24U) & DUK_U64_CONSTANT(0xff0000)) | \ -+ ((((duk_uint64_t) (x)) >> 8U) & DUK_U64_CONSTANT(0xff000000)) | \ -+ ((((duk_uint64_t) (x)) << 8U) & DUK_U64_CONSTANT(0xff00000000)) | \ -+ ((((duk_uint64_t) (x)) << 24U) & DUK_U64_CONSTANT(0xff0000000000)) | \ -+ ((((duk_uint64_t) (x)) << 40U) & DUK_U64_CONSTANT(0xff000000000000)) | \ -+ (((duk_uint64_t) (x)) << 56U)) -+#endif -+#endif -+#if !defined(DUK_BSWAP32) -+#define DUK_BSWAP32(x) \ -+ ((((duk_uint32_t) (x)) >> 24U) | \ -+ ((((duk_uint32_t) (x)) >> 8U) & 0xff00UL) | \ -+ ((((duk_uint32_t) (x)) << 8U) & 0xff0000UL) | \ -+ (((duk_uint32_t) (x)) << 24U)) -+#endif -+#if !defined(DUK_BSWAP16) -+#define DUK_BSWAP16(x) \ -+ ((duk_uint16_t) (x) >> 8U) | \ -+ ((duk_uint16_t) (x) << 8U) -+#endif -+ -+/* DUK_USE_VARIADIC_MACROS: required from compilers, so no fill-in. */ -+/* DUK_USE_UNION_INITIALIZERS: required from compilers, so no fill-in. */ -+ -+#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE)) -+#if defined(DUK_F_C99) -+#define DUK_USE_FLEX_C99 -+#else -+#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */ -+#endif -+#endif -+ -+#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \ -+ defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER)) -+#define DUK_USE_PACK_DUMMY_MEMBER -+#endif -+ -+#if 0 /* not defined by default */ -+#undef DUK_USE_GCC_PRAGMAS -+#endif -diff --git a/dist/source/config/header-snippets/cpp_exception_sanity.h.in b/dist/source/config/header-snippets/cpp_exception_sanity.h.in -new file mode 100644 -index 0000000..334f926 ---- /dev/null -+++ b/dist/source/config/header-snippets/cpp_exception_sanity.h.in -@@ -0,0 +1,3 @@ -+#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus) -+#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler -+#endif -diff --git a/dist/source/config/header-snippets/date_provider.h.in b/dist/source/config/header-snippets/date_provider.h.in -new file mode 100644 -index 0000000..15a4ac7 ---- /dev/null -+++ b/dist/source/config/header-snippets/date_provider.h.in -@@ -0,0 +1,66 @@ -+/* -+ * Date provider selection -+ * -+ * User may define DUK_USE_DATE_GET_NOW() etc directly, in which case we'll -+ * rely on an external provider. If this is not done, revert to previous -+ * behavior and use Unix/Windows built-in provider. -+ */ -+ -+#if defined(DUK_COMPILING_DUKTAPE) -+ -+#if defined(DUK_USE_DATE_GET_NOW) -+/* External provider already defined. */ -+#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) -+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday() -+#elif defined(DUK_USE_DATE_NOW_TIME) -+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time() -+#elif defined(DUK_USE_DATE_NOW_WINDOWS) -+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows() -+#elif defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) -+#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows_subms() -+#else -+#error no provider for DUK_USE_DATE_GET_NOW() -+#endif -+ -+#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET) -+/* External provider already defined. */ -+#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) -+#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d)) -+#elif defined(DUK_USE_DATE_TZO_WINDOWS) -+#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d)) -+#elif defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) -+#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows_no_dst((d)) -+#else -+#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET() -+#endif -+ -+#if defined(DUK_USE_DATE_PARSE_STRING) -+/* External provider already defined. */ -+#elif defined(DUK_USE_DATE_PRS_STRPTIME) -+#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str)) -+#elif defined(DUK_USE_DATE_PRS_GETDATE) -+#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str)) -+#else -+/* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */ -+#endif -+ -+#if defined(DUK_USE_DATE_FORMAT_STRING) -+/* External provider already defined. */ -+#elif defined(DUK_USE_DATE_FMT_STRFTIME) -+#define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \ -+ duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags)) -+#else -+/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */ -+#endif -+ -+#if defined(DUK_USE_GET_MONOTONIC_TIME) -+/* External provider already defined. */ -+#elif defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME) -+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_clock_gettime() -+#elif defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) -+#define DUK_USE_GET_MONOTONIC_TIME(ctx) duk_bi_date_get_monotonic_time_windows_qpc() -+#else -+/* No provider for DUK_USE_GET_MONOTONIC_TIME(), fall back to DUK_USE_DATE_GET_NOW(). */ -+#endif -+ -+#endif /* DUK_COMPILING_DUKTAPE */ -diff --git a/dist/source/config/header-snippets/gcc_clang_visibility.h.in b/dist/source/config/header-snippets/gcc_clang_visibility.h.in -new file mode 100644 -index 0000000..7e806e2 ---- /dev/null -+++ b/dist/source/config/header-snippets/gcc_clang_visibility.h.in -@@ -0,0 +1,26 @@ -+#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern -+#define DUK_EXTERNAL __attribute__ ((visibility("default"))) -+#if defined(DUK_SINGLE_FILE) -+#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -+/* Minimize warnings for unused internal functions with GCC >= 3.1.1 and -+ * Clang. Based on documentation it should suffice to have the attribute -+ * in the declaration only, but in practice some warnings are generated unless -+ * the attribute is also applied to the definition. -+ */ -+#define DUK_INTERNAL_DECL static __attribute__ ((unused)) -+#define DUK_INTERNAL static __attribute__ ((unused)) -+#else -+#define DUK_INTERNAL_DECL static -+#define DUK_INTERNAL static -+#endif -+#else -+#if (defined(DUK_F_GCC_VERSION) && DUK_F_GCC_VERSION >= 30101) || defined(DUK_F_CLANG) -+#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) extern -+#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) __attribute__ ((unused)) -+#else -+#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern -+#define DUK_INTERNAL __attribute__ ((visibility("hidden"))) -+#endif -+#endif -+#define DUK_LOCAL_DECL static -+#define DUK_LOCAL static -diff --git a/dist/source/config/header-snippets/inline_workaround.h.in b/dist/source/config/header-snippets/inline_workaround.h.in -new file mode 100644 -index 0000000..75587c9 ---- /dev/null -+++ b/dist/source/config/header-snippets/inline_workaround.h.in -@@ -0,0 +1,11 @@ -+/* Workaround for GH-323: avoid inlining control when compiling from -+ * multiple sources, as it causes compiler portability trouble. -+ */ -+#if !defined(DUK_SINGLE_FILE) -+#undef DUK_NOINLINE -+#undef DUK_INLINE -+#undef DUK_ALWAYS_INLINE -+#define DUK_NOINLINE /*nop*/ -+#define DUK_INLINE /*nop*/ -+#define DUK_ALWAYS_INLINE /*nop*/ -+#endif -diff --git a/dist/source/config/header-snippets/msvc_visibility.h.in b/dist/source/config/header-snippets/msvc_visibility.h.in -new file mode 100644 -index 0000000..332a2b2 ---- /dev/null -+++ b/dist/source/config/header-snippets/msvc_visibility.h.in -@@ -0,0 +1,19 @@ -+/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're -+ * compiling Duktape or the application. -+ */ -+#if defined(DUK_COMPILING_DUKTAPE) -+#define DUK_EXTERNAL_DECL extern __declspec(dllexport) -+#define DUK_EXTERNAL __declspec(dllexport) -+#else -+#define DUK_EXTERNAL_DECL extern __declspec(dllimport) -+#define DUK_EXTERNAL should_not_happen -+#endif -+#if defined(DUK_SINGLE_FILE) -+#define DUK_INTERNAL_DECL static -+#define DUK_INTERNAL static -+#else -+#define DUK_INTERNAL_DECL extern -+#define DUK_INTERNAL /*empty*/ -+#endif -+#define DUK_LOCAL_DECL static -+#define DUK_LOCAL static -diff --git a/dist/source/config/header-snippets/object_layout.h.in b/dist/source/config/header-snippets/object_layout.h.in -new file mode 100644 -index 0000000..7b01c0a ---- /dev/null -+++ b/dist/source/config/header-snippets/object_layout.h.in -@@ -0,0 +1,21 @@ -+/* Object property allocation layout has implications for memory and code -+ * footprint and generated code size/speed. The best layout also depends -+ * on whether the platform has alignment requirements or benefits from -+ * having mostly aligned accesses. -+ */ -+#undef DUK_USE_HOBJECT_LAYOUT_1 -+#undef DUK_USE_HOBJECT_LAYOUT_2 -+#undef DUK_USE_HOBJECT_LAYOUT_3 -+#if (DUK_USE_ALIGN_BY == 1) -+/* On platforms without any alignment issues, layout 1 is preferable -+ * because it compiles to slightly less code and provides direct access -+ * to property keys. -+ */ -+#define DUK_USE_HOBJECT_LAYOUT_1 -+#else -+/* On other platforms use layout 2, which requires some padding but -+ * is a bit more natural than layout 3 in ordering the entries. Layout -+ * 3 is currently not used. -+ */ -+#define DUK_USE_HOBJECT_LAYOUT_2 -+#endif -diff --git a/dist/source/config/header-snippets/packed_tval_fillin.h.in b/dist/source/config/header-snippets/packed_tval_fillin.h.in -new file mode 100644 -index 0000000..3acdc20 ---- /dev/null -+++ b/dist/source/config/header-snippets/packed_tval_fillin.h.in -@@ -0,0 +1,40 @@ -+/* -+ * Check whether or not a packed duk_tval representation is possible. -+ * What's basically required is that pointers are 32-bit values -+ * (sizeof(void *) == 4). Best effort check, not always accurate. -+ * If guess goes wrong, crashes may result; self tests also verify -+ * the guess. -+ */ -+ -+/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */ -+#if !defined(DUK_F_PACKED_TVAL_PROVIDED) -+#undef DUK_F_PACKED_TVAL_POSSIBLE -+ -+/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */ -+#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) -+#if (DUK_UINTPTR_MAX <= 0xffffffffUL) -+#define DUK_F_PACKED_TVAL_POSSIBLE -+#endif -+#endif -+ -+/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */ -+#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED) -+#if (DUK_UINTPTR_MAX <= 0xffffffffUL) -+#define DUK_F_PACKED_TVAL_POSSIBLE -+#endif -+#endif -+ -+/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */ -+#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED) -+#if (DUK_SIZE_MAX <= 0xffffffffUL) -+#define DUK_F_PACKED_TVAL_POSSIBLE -+#endif -+#endif -+ -+#undef DUK_USE_PACKED_TVAL -+#if defined(DUK_F_PACKED_TVAL_POSSIBLE) -+#define DUK_USE_PACKED_TVAL -+#endif -+#undef DUK_F_PACKED_TVAL_POSSIBLE -+ -+#endif /* DUK_F_PACKED_TVAL_PROVIDED */ -diff --git a/dist/source/config/header-snippets/platform_conditionalincludes.h.in b/dist/source/config/header-snippets/platform_conditionalincludes.h.in -new file mode 100644 -index 0000000..0ad50b3 ---- /dev/null -+++ b/dist/source/config/header-snippets/platform_conditionalincludes.h.in -@@ -0,0 +1,4 @@ -+#if defined(DUK_F_CPP) && defined(DUK_USE_CPP_EXCEPTIONS) -+#include /* std::exception */ -+#include /* std::runtime_error */ -+#endif -diff --git a/dist/source/config/header-snippets/platform_cppextras.h.in b/dist/source/config/header-snippets/platform_cppextras.h.in -new file mode 100644 -index 0000000..2beccfd ---- /dev/null -+++ b/dist/source/config/header-snippets/platform_cppextras.h.in -@@ -0,0 +1,9 @@ -+/* Workaround for older C++ compilers before including , -+ * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366 -+ */ -+#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS) -+#define __STDC_LIMIT_MACROS -+#endif -+#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) -+#define __STDC_CONSTANT_MACROS -+#endif -diff --git a/dist/source/config/header-snippets/platform_fillins.h.in b/dist/source/config/header-snippets/platform_fillins.h.in -new file mode 100644 -index 0000000..be209b8 ---- /dev/null -+++ b/dist/source/config/header-snippets/platform_fillins.h.in -@@ -0,0 +1,327 @@ -+/* An abort()-like primitive is needed by the default fatal error handler. */ -+#if !defined(DUK_ABORT) -+#define DUK_ABORT abort -+#endif -+ -+#if !defined(DUK_SETJMP) -+#define DUK_JMPBUF_TYPE jmp_buf -+#define DUK_SETJMP(jb) setjmp((jb)) -+#define DUK_LONGJMP(jb) longjmp((jb), 1) -+#endif -+ -+#if 0 -+/* sigsetjmp() alternative */ -+#define DUK_JMPBUF_TYPE sigjmp_buf -+#define DUK_SETJMP(jb) sigsetjmp((jb)) -+#define DUK_LONGJMP(jb) siglongjmp((jb), 1) -+#endif -+ -+/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h -+ * (which is unfortunately named). May sometimes need replacement, e.g. -+ * some compilers don't handle zero length or NULL correctly in realloc(). -+ */ -+#if !defined(DUK_ANSI_MALLOC) -+#define DUK_ANSI_MALLOC malloc -+#endif -+#if !defined(DUK_ANSI_REALLOC) -+#define DUK_ANSI_REALLOC realloc -+#endif -+#if !defined(DUK_ANSI_CALLOC) -+#define DUK_ANSI_CALLOC calloc -+#endif -+#if !defined(DUK_ANSI_FREE) -+#define DUK_ANSI_FREE free -+#endif -+ -+/* ANSI C (various versions) and some implementations require that the -+ * pointer arguments to memset(), memcpy(), and memmove() be valid values -+ * even when byte size is 0 (even a NULL pointer is considered invalid in -+ * this context). Zero-size operations as such are allowed, as long as their -+ * pointer arguments point to a valid memory area. The DUK_MEMSET(), -+ * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.: -+ * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be -+ * allowed. If these are not fulfilled, a macro wrapper is needed. -+ * -+ * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 -+ * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html -+ * -+ * Not sure what's the required behavior when a pointer points just past the -+ * end of a buffer, which often happens in practice (e.g. zero size memmoves). -+ * For example, if allocation size is 3, the following pointer would not -+ * technically point to a valid memory byte: -+ * -+ * <-- alloc --> -+ * | 0 | 1 | 2 | ..... -+ * ^-- p=3, points after last valid byte (2) -+ */ -+#if !defined(DUK_MEMCPY) -+#if defined(DUK_F_UCLIBC) -+/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide -+ * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html -+ */ -+#define DUK_MEMCPY memmove -+#else -+#define DUK_MEMCPY memcpy -+#endif -+#endif -+#if !defined(DUK_MEMMOVE) -+#define DUK_MEMMOVE memmove -+#endif -+#if !defined(DUK_MEMCMP) -+#define DUK_MEMCMP memcmp -+#endif -+#if !defined(DUK_MEMSET) -+#define DUK_MEMSET memset -+#endif -+#if !defined(DUK_STRLEN) -+#define DUK_STRLEN strlen -+#endif -+#if !defined(DUK_STRCMP) -+#define DUK_STRCMP strcmp -+#endif -+#if !defined(DUK_STRNCMP) -+#define DUK_STRNCMP strncmp -+#endif -+#if !defined(DUK_SPRINTF) -+#define DUK_SPRINTF sprintf -+#endif -+#if !defined(DUK_SNPRINTF) -+/* snprintf() is technically not part of C89 but usually available. */ -+#define DUK_SNPRINTF snprintf -+#endif -+#if !defined(DUK_VSPRINTF) -+#define DUK_VSPRINTF vsprintf -+#endif -+#if !defined(DUK_VSNPRINTF) -+/* vsnprintf() is technically not part of C89 but usually available. */ -+#define DUK_VSNPRINTF vsnprintf -+#endif -+#if !defined(DUK_SSCANF) -+#define DUK_SSCANF sscanf -+#endif -+#if !defined(DUK_VSSCANF) -+#define DUK_VSSCANF vsscanf -+#endif -+#if !defined(DUK_MEMZERO) -+#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n)) -+#endif -+ -+#if !defined(DUK_DOUBLE_INFINITY) -+#undef DUK_USE_COMPUTED_INFINITY -+#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600) -+/* GCC older than 4.6: avoid overflow warnings related to using INFINITY */ -+#define DUK_DOUBLE_INFINITY (__builtin_inf()) -+#elif defined(INFINITY) -+#define DUK_DOUBLE_INFINITY ((double) INFINITY) -+#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ -+ !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) -+#define DUK_DOUBLE_INFINITY (1.0 / 0.0) -+#else -+/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity. -+ * Use a computed infinity (initialized when a heap is created at the -+ * latest). -+ */ -+#define DUK_USE_COMPUTED_INFINITY -+#define DUK_DOUBLE_INFINITY duk_computed_infinity -+#endif -+#endif -+ -+#if !defined(DUK_DOUBLE_NAN) -+#undef DUK_USE_COMPUTED_NAN -+#if defined(NAN) -+#define DUK_DOUBLE_NAN NAN -+#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC) && \ -+ !defined(DUK_F_OLD_SOLARIS) && !defined(DUK_F_AIX) -+#define DUK_DOUBLE_NAN (0.0 / 0.0) -+#else -+/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN. -+ * In MSVC (VS2010 Express) (0.0 / 0.0) results in a compile error. -+ * Use a computed NaN (initialized when a heap is created at the -+ * latest). -+ */ -+#define DUK_USE_COMPUTED_NAN -+#define DUK_DOUBLE_NAN duk_computed_nan -+#endif -+#endif -+ -+/* Many platforms are missing fpclassify() and friends, so use replacements -+ * if necessary. The replacement constants (FP_NAN etc) can be anything but -+ * match Linux constants now. -+ */ -+#undef DUK_USE_REPL_FPCLASSIFY -+#undef DUK_USE_REPL_SIGNBIT -+#undef DUK_USE_REPL_ISFINITE -+#undef DUK_USE_REPL_ISNAN -+#undef DUK_USE_REPL_ISINF -+ -+/* Complex condition broken into separate parts. */ -+#undef DUK_F_USE_REPL_ALL -+#if !(defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) && \ -+ defined(FP_SUBNORMAL) && defined(FP_NORMAL)) -+/* Missing some obvious constants. */ -+#define DUK_F_USE_REPL_ALL -+#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC) -+/* VBCC is missing the built-ins even in C99 mode (perhaps a header issue). */ -+#define DUK_F_USE_REPL_ALL -+#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_M68K) -+/* AmigaOS + M68K seems to have math issues even when using GCC cross -+ * compilation. Use replacements for all AmigaOS versions on M68K -+ * regardless of compiler. -+ */ -+#define DUK_F_USE_REPL_ALL -+#elif defined(DUK_F_FREEBSD) && defined(DUK_F_CLANG) -+/* Placeholder fix for (detection is wider than necessary): -+ * http://llvm.org/bugs/show_bug.cgi?id=17788 -+ */ -+#define DUK_F_USE_REPL_ALL -+#elif defined(DUK_F_UCLIBC) -+/* At least some uclibc versions have broken floating point math. For -+ * example, fpclassify() can incorrectly classify certain NaN formats. -+ * To be safe, use replacements. -+ */ -+#define DUK_F_USE_REPL_ALL -+#elif defined(DUK_F_AIX) -+/* Older versions may be missing isnan(), etc. */ -+#define DUK_F_USE_REPL_ALL -+#endif -+ -+#if defined(DUK_F_USE_REPL_ALL) -+#define DUK_USE_REPL_FPCLASSIFY -+#define DUK_USE_REPL_SIGNBIT -+#define DUK_USE_REPL_ISFINITE -+#define DUK_USE_REPL_ISNAN -+#define DUK_USE_REPL_ISINF -+#define DUK_FPCLASSIFY duk_repl_fpclassify -+#define DUK_SIGNBIT duk_repl_signbit -+#define DUK_ISFINITE duk_repl_isfinite -+#define DUK_ISNAN duk_repl_isnan -+#define DUK_ISINF duk_repl_isinf -+#define DUK_FP_NAN 0 -+#define DUK_FP_INFINITE 1 -+#define DUK_FP_ZERO 2 -+#define DUK_FP_SUBNORMAL 3 -+#define DUK_FP_NORMAL 4 -+#else -+#define DUK_FPCLASSIFY fpclassify -+#define DUK_SIGNBIT signbit -+#define DUK_ISFINITE isfinite -+#define DUK_ISNAN isnan -+#define DUK_ISINF isinf -+#define DUK_FP_NAN FP_NAN -+#define DUK_FP_INFINITE FP_INFINITE -+#define DUK_FP_ZERO FP_ZERO -+#define DUK_FP_SUBNORMAL FP_SUBNORMAL -+#define DUK_FP_NORMAL FP_NORMAL -+#endif -+ -+#if defined(DUK_F_USE_REPL_ALL) -+#undef DUK_F_USE_REPL_ALL -+#endif -+ -+/* These functions don't currently need replacement but are wrapped for -+ * completeness. Because these are used as function pointers, they need -+ * to be defined as concrete C functions (not macros). -+ */ -+#if !defined(DUK_FABS) -+#define DUK_FABS fabs -+#endif -+#if !defined(DUK_FLOOR) -+#define DUK_FLOOR floor -+#endif -+#if !defined(DUK_CEIL) -+#define DUK_CEIL ceil -+#endif -+#if !defined(DUK_FMOD) -+#define DUK_FMOD fmod -+#endif -+#if !defined(DUK_POW) -+#define DUK_POW pow -+#endif -+#if !defined(DUK_ACOS) -+#define DUK_ACOS acos -+#endif -+#if !defined(DUK_ASIN) -+#define DUK_ASIN asin -+#endif -+#if !defined(DUK_ATAN) -+#define DUK_ATAN atan -+#endif -+#if !defined(DUK_ATAN2) -+#define DUK_ATAN2 atan2 -+#endif -+#if !defined(DUK_SIN) -+#define DUK_SIN sin -+#endif -+#if !defined(DUK_COS) -+#define DUK_COS cos -+#endif -+#if !defined(DUK_TAN) -+#define DUK_TAN tan -+#endif -+#if !defined(DUK_EXP) -+#define DUK_EXP exp -+#endif -+#if !defined(DUK_LOG) -+#define DUK_LOG log -+#endif -+#if !defined(DUK_SQRT) -+#define DUK_SQRT sqrt -+#endif -+ -+/* The functions below exist only in C99/C++11 or later and need a workaround -+ * for platforms that don't include them. MSVC isn't detected as C99, but -+ * these functions also exist in MSVC 2013 and later so include a clause for -+ * that too. Android doesn't have log2; disable all of these for Android. -+ */ -+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11) || (defined(_MSC_VER) && (_MSC_VER >= 1800))) && \ -+ !defined(DUK_F_ANDROID) && !defined(DUK_F_MINT) -+#if !defined(DUK_CBRT) -+#define DUK_CBRT cbrt -+#endif -+#if !defined(DUK_LOG2) -+#define DUK_LOG2 log2 -+#endif -+#if !defined(DUK_LOG10) -+#define DUK_LOG10 log10 -+#endif -+#if !defined(DUK_TRUNC) -+#define DUK_TRUNC trunc -+#endif -+#endif /* DUK_F_C99 etc */ -+ -+/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics, -+ * see test-bug-netbsd-math-pow.js. MinGW has similar (but different) -+ * issues, see test-bug-mingw-math-issues.js. Enable pow() workarounds -+ * for these targets. -+ */ -+#undef DUK_USE_POW_WORKAROUNDS -+#if defined(DUK_F_NETBSD) || defined(DUK_F_MINGW) -+#define DUK_USE_POW_WORKAROUNDS -+#endif -+ -+/* Similar workarounds for atan2() semantics issues. MinGW issues are -+ * documented in test-bug-mingw-math-issues.js. -+ */ -+#undef DUK_USE_ATAN2_WORKAROUNDS -+#if defined(DUK_F_MINGW) -+#define DUK_USE_ATAN2_WORKAROUNDS -+#endif -+ -+/* Rely as little as possible on compiler behavior for NaN comparison, -+ * signed zero handling, etc. Currently never activated but may be needed -+ * for broken compilers. -+ */ -+#undef DUK_USE_PARANOID_MATH -+ -+/* There was a curious bug where test-bi-date-canceling.js would fail e.g. -+ * on 64-bit Ubuntu, gcc-4.8.1, -m32, and no -std=c99. Some date computations -+ * using doubles would be optimized which then broke some corner case tests. -+ * The problem goes away by adding 'volatile' to the datetime computations. -+ * Not sure what the actual triggering conditions are, but using this on -+ * non-C99 systems solves the known issues and has relatively little cost -+ * on other platforms. -+ */ -+#undef DUK_USE_PARANOID_DATE_COMPUTATION -+#if !defined(DUK_F_C99) -+#define DUK_USE_PARANOID_DATE_COMPUTATION -+#endif -diff --git a/dist/source/config/header-snippets/platform_sharedincludes.h.in b/dist/source/config/header-snippets/platform_sharedincludes.h.in -new file mode 100644 -index 0000000..4a3b8e3 ---- /dev/null -+++ b/dist/source/config/header-snippets/platform_sharedincludes.h.in -@@ -0,0 +1,24 @@ -+/* Shared includes: C89 */ -+#include -+#include -+#include -+#include /* varargs */ -+#include -+#include /* e.g. ptrdiff_t */ -+#include -+#include -+ -+/* date.h is omitted, and included per platform */ -+ -+/* Shared includes: stdint.h is C99 */ -+#if defined(DUK_F_NO_STDINT_H) -+/* stdint.h not available */ -+#else -+/* Technically C99 (C++11) but found in many systems. On some systems -+ * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before -+ * including stdint.h (see above). -+ */ -+#include -+#endif -+ -+/* is only included if needed, based on DUK_USE_xxx flags. */ -diff --git a/dist/source/config/header-snippets/reject_fast_math.h.in b/dist/source/config/header-snippets/reject_fast_math.h.in -new file mode 100644 -index 0000000..d842023 ---- /dev/null -+++ b/dist/source/config/header-snippets/reject_fast_math.h.in -@@ -0,0 +1,6 @@ -+/* GCC/clang inaccurate math would break compliance and probably duk_tval, -+ * so refuse to compile. Relax this if -ffast-math is tested to work. -+ */ -+#if defined(__FAST_MATH__) -+#error __FAST_MATH__ defined, refusing to compile -+#endif -diff --git a/dist/source/config/header-snippets/types1.h.in b/dist/source/config/header-snippets/types1.h.in -new file mode 100644 -index 0000000..5544dae ---- /dev/null -+++ b/dist/source/config/header-snippets/types1.h.in -@@ -0,0 +1,78 @@ -+/* -+ * Wrapper typedefs and constants for integer types, also sanity check types. -+ * -+ * C99 typedefs are quite good but not always available, and we want to avoid -+ * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for -+ * all C99 typedefs and Duktape code should only use these typedefs. Type -+ * detection when C99 is not supported is best effort and may end up detecting -+ * some types incorrectly. -+ * -+ * Pointer sizes are a portability problem: pointers to different types may -+ * have a different size and function pointers are very difficult to manage -+ * portably. -+ * -+ * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types -+ * -+ * Note: there's an interesting corner case when trying to define minimum -+ * signed integer value constants which leads to the current workaround of -+ * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt -+ * for a longer discussion. -+ * -+ * Note: avoid typecasts and computations in macro integer constants as they -+ * can then no longer be used in macro relational expressions (such as -+ * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on -+ * being able to compare DUK_SIZE_MAX against a limit. -+ */ -+ -+/* XXX: add feature options to force basic types from outside? */ -+ -+#if !defined(INT_MAX) -+#error INT_MAX not defined -+#endif -+ -+/* Check that architecture is two's complement, standard C allows e.g. -+ * INT_MIN to be -2**31+1 (instead of -2**31). -+ */ -+#if defined(INT_MAX) && defined(INT_MIN) -+#if INT_MAX != -(INT_MIN + 1) -+#error platform does not seem complement of two -+#endif -+#else -+#error cannot check complement of two -+#endif -+ -+/* Pointer size determination based on __WORDSIZE or architecture when -+ * that's not available. -+ */ -+#if defined(DUK_F_X86) || defined(DUK_F_X32) || \ -+ defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \ -+ defined(DUK_F_BCC) || \ -+ (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \ -+ ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ -+ defined(DUK_F_HPUX)) && defined(_ILP32)) || \ -+ defined(DUK_F_ARM32) -+#define DUK_F_32BIT_PTRS -+#elif defined(DUK_F_X64) || \ -+ (defined(__WORDSIZE) && (__WORDSIZE == 64)) || \ -+ ((defined(DUK_F_OLD_SOLARIS) || defined(DUK_F_AIX) || \ -+ defined(DUK_F_HPUX)) && defined(_LP64)) || \ -+ defined(DUK_F_ARM64) -+#define DUK_F_64BIT_PTRS -+#else -+/* not sure, not needed with C99 anyway */ -+#endif -+ -+/* Intermediate define for 'have inttypes.h' */ -+#undef DUK_F_HAVE_INTTYPES -+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ -+ !(defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)) -+/* vbcc + AmigaOS has C99 but no inttypes.h */ -+#define DUK_F_HAVE_INTTYPES -+#elif defined(__cplusplus) && (__cplusplus >= 201103L) -+/* C++11 apparently ratified stdint.h */ -+#define DUK_F_HAVE_INTTYPES -+#endif -+ -+/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise -+ * through automatic detection. -+ */ -diff --git a/dist/source/config/header-snippets/types2.h.in b/dist/source/config/header-snippets/types2.h.in -new file mode 100644 -index 0000000..39eaf32 ---- /dev/null -+++ b/dist/source/config/header-snippets/types2.h.in -@@ -0,0 +1,132 @@ -+/* A few types are assumed to always exist. */ -+typedef size_t duk_size_t; -+typedef ptrdiff_t duk_ptrdiff_t; -+ -+/* The best type for an "all around int" in Duktape internals is "at least -+ * 32 bit signed integer" which is most convenient. Same for unsigned type. -+ * Prefer 'int' when large enough, as it is almost always a convenient type. -+ */ -+#if defined(UINT_MAX) && (UINT_MAX >= 0xffffffffUL) -+typedef int duk_int_t; -+typedef unsigned int duk_uint_t; -+#define DUK_INT_MIN INT_MIN -+#define DUK_INT_MAX INT_MAX -+#define DUK_UINT_MIN 0 -+#define DUK_UINT_MAX UINT_MAX -+#else -+typedef duk_int_fast32_t duk_int_t; -+typedef duk_uint_fast32_t duk_uint_t; -+#define DUK_INT_MIN DUK_INT_FAST32_MIN -+#define DUK_INT_MAX DUK_INT_FAST32_MAX -+#define DUK_UINT_MIN DUK_UINT_FAST32_MIN -+#define DUK_UINT_MAX DUK_UINT_FAST32_MAX -+#endif -+ -+/* Same as 'duk_int_t' but guaranteed to be a 'fast' variant if this -+ * distinction matters for the CPU. These types are used mainly in the -+ * executor where it might really matter. -+ */ -+typedef duk_int_fast32_t duk_int_fast_t; -+typedef duk_uint_fast32_t duk_uint_fast_t; -+#define DUK_INT_FAST_MIN DUK_INT_FAST32_MIN -+#define DUK_INT_FAST_MAX DUK_INT_FAST32_MAX -+#define DUK_UINT_FAST_MIN DUK_UINT_FAST32_MIN -+#define DUK_UINT_FAST_MAX DUK_UINT_FAST32_MAX -+ -+/* Small integers (16 bits or more) can fall back to the 'int' type, but -+ * have a typedef so they are marked "small" explicitly. -+ */ -+typedef int duk_small_int_t; -+typedef unsigned int duk_small_uint_t; -+#define DUK_SMALL_INT_MIN INT_MIN -+#define DUK_SMALL_INT_MAX INT_MAX -+#define DUK_SMALL_UINT_MIN 0 -+#define DUK_SMALL_UINT_MAX UINT_MAX -+ -+/* Fast variants of small integers, again for really fast paths like the -+ * executor. -+ */ -+typedef duk_int_fast16_t duk_small_int_fast_t; -+typedef duk_uint_fast16_t duk_small_uint_fast_t; -+#define DUK_SMALL_INT_FAST_MIN DUK_INT_FAST16_MIN -+#define DUK_SMALL_INT_FAST_MAX DUK_INT_FAST16_MAX -+#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN -+#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX -+ -+/* Boolean values are represented with the platform 'unsigned int'. */ -+typedef duk_small_uint_t duk_bool_t; -+#define DUK_BOOL_MIN DUK_SMALL_UINT_MIN -+#define DUK_BOOL_MAX DUK_SMALL_UINT_MAX -+ -+/* Index values must have at least 32-bit signed range. */ -+typedef duk_int_t duk_idx_t; -+#define DUK_IDX_MIN DUK_INT_MIN -+#define DUK_IDX_MAX DUK_INT_MAX -+ -+/* Unsigned index variant. */ -+typedef duk_uint_t duk_uidx_t; -+#define DUK_UIDX_MIN DUK_UINT_MIN -+#define DUK_UIDX_MAX DUK_UINT_MAX -+ -+/* Array index values, could be exact 32 bits. -+ * Currently no need for signed duk_arridx_t. -+ */ -+typedef duk_uint_t duk_uarridx_t; -+#define DUK_UARRIDX_MIN DUK_UINT_MIN -+#define DUK_UARRIDX_MAX DUK_UINT_MAX -+ -+/* Duktape/C function return value, platform int is enough for now to -+ * represent 0, 1, or negative error code. Must be compatible with -+ * assigning truth values (e.g. duk_ret_t rc = (foo == bar);). -+ */ -+typedef duk_small_int_t duk_ret_t; -+#define DUK_RET_MIN DUK_SMALL_INT_MIN -+#define DUK_RET_MAX DUK_SMALL_INT_MAX -+ -+/* Error codes are represented with platform int. High bits are used -+ * for flags and such, so 32 bits are needed. -+ */ -+typedef duk_int_t duk_errcode_t; -+#define DUK_ERRCODE_MIN DUK_INT_MIN -+#define DUK_ERRCODE_MAX DUK_INT_MAX -+ -+/* Codepoint type. Must be 32 bits or more because it is used also for -+ * internal codepoints. The type is signed because negative codepoints -+ * are used as internal markers (e.g. to mark EOF or missing argument). -+ * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to -+ * ensure duk_uint32_t casts back and forth nicely. Almost everything -+ * else uses the signed one. -+ */ -+typedef duk_int_t duk_codepoint_t; -+typedef duk_uint_t duk_ucodepoint_t; -+#define DUK_CODEPOINT_MIN DUK_INT_MIN -+#define DUK_CODEPOINT_MAX DUK_INT_MAX -+#define DUK_UCODEPOINT_MIN DUK_UINT_MIN -+#define DUK_UCODEPOINT_MAX DUK_UINT_MAX -+ -+/* IEEE float/double typedef. */ -+typedef float duk_float_t; -+typedef double duk_double_t; -+ -+/* We're generally assuming that we're working on a platform with a 32-bit -+ * address space. If DUK_SIZE_MAX is a typecast value (which is necessary -+ * if SIZE_MAX is missing), the check must be avoided because the -+ * preprocessor can't do a comparison. -+ */ -+#if !defined(DUK_SIZE_MAX) -+#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX -+#elif !defined(DUK_SIZE_MAX_COMPUTED) -+#if DUK_SIZE_MAX < 0xffffffffUL -+/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value -+ * which seems incorrect if size_t is (at least) an unsigned 32-bit type. -+ * However, it doesn't seem useful to error out compilation if this is the -+ * case. -+ */ -+#endif -+#endif -+ -+/* Type used in public API declarations and user code. Typedef maps to -+ * 'struct duk_hthread' like the 'duk_hthread' typedef which is used -+ * exclusively in internals. -+ */ -+typedef struct duk_hthread duk_context; -diff --git a/dist/source/config/header-snippets/types_c99.h.in b/dist/source/config/header-snippets/types_c99.h.in -new file mode 100644 -index 0000000..62afeab ---- /dev/null -+++ b/dist/source/config/header-snippets/types_c99.h.in -@@ -0,0 +1,95 @@ -+#define DUK_F_HAVE_64BIT -+#include -+ -+typedef uint8_t duk_uint8_t; -+typedef int8_t duk_int8_t; -+typedef uint16_t duk_uint16_t; -+typedef int16_t duk_int16_t; -+typedef uint32_t duk_uint32_t; -+typedef int32_t duk_int32_t; -+typedef uint64_t duk_uint64_t; -+typedef int64_t duk_int64_t; -+typedef uint_least8_t duk_uint_least8_t; -+typedef int_least8_t duk_int_least8_t; -+typedef uint_least16_t duk_uint_least16_t; -+typedef int_least16_t duk_int_least16_t; -+typedef uint_least32_t duk_uint_least32_t; -+typedef int_least32_t duk_int_least32_t; -+typedef uint_least64_t duk_uint_least64_t; -+typedef int_least64_t duk_int_least64_t; -+typedef uint_fast8_t duk_uint_fast8_t; -+typedef int_fast8_t duk_int_fast8_t; -+typedef uint_fast16_t duk_uint_fast16_t; -+typedef int_fast16_t duk_int_fast16_t; -+typedef uint_fast32_t duk_uint_fast32_t; -+typedef int_fast32_t duk_int_fast32_t; -+typedef uint_fast64_t duk_uint_fast64_t; -+typedef int_fast64_t duk_int_fast64_t; -+typedef uintptr_t duk_uintptr_t; -+typedef intptr_t duk_intptr_t; -+typedef uintmax_t duk_uintmax_t; -+typedef intmax_t duk_intmax_t; -+ -+#define DUK_UINT8_MIN 0 -+#define DUK_UINT8_MAX UINT8_MAX -+#define DUK_INT8_MIN INT8_MIN -+#define DUK_INT8_MAX INT8_MAX -+#define DUK_UINT_LEAST8_MIN 0 -+#define DUK_UINT_LEAST8_MAX UINT_LEAST8_MAX -+#define DUK_INT_LEAST8_MIN INT_LEAST8_MIN -+#define DUK_INT_LEAST8_MAX INT_LEAST8_MAX -+#define DUK_UINT_FAST8_MIN 0 -+#define DUK_UINT_FAST8_MAX UINT_FAST8_MAX -+#define DUK_INT_FAST8_MIN INT_FAST8_MIN -+#define DUK_INT_FAST8_MAX INT_FAST8_MAX -+#define DUK_UINT16_MIN 0 -+#define DUK_UINT16_MAX UINT16_MAX -+#define DUK_INT16_MIN INT16_MIN -+#define DUK_INT16_MAX INT16_MAX -+#define DUK_UINT_LEAST16_MIN 0 -+#define DUK_UINT_LEAST16_MAX UINT_LEAST16_MAX -+#define DUK_INT_LEAST16_MIN INT_LEAST16_MIN -+#define DUK_INT_LEAST16_MAX INT_LEAST16_MAX -+#define DUK_UINT_FAST16_MIN 0 -+#define DUK_UINT_FAST16_MAX UINT_FAST16_MAX -+#define DUK_INT_FAST16_MIN INT_FAST16_MIN -+#define DUK_INT_FAST16_MAX INT_FAST16_MAX -+#define DUK_UINT32_MIN 0 -+#define DUK_UINT32_MAX UINT32_MAX -+#define DUK_INT32_MIN INT32_MIN -+#define DUK_INT32_MAX INT32_MAX -+#define DUK_UINT_LEAST32_MIN 0 -+#define DUK_UINT_LEAST32_MAX UINT_LEAST32_MAX -+#define DUK_INT_LEAST32_MIN INT_LEAST32_MIN -+#define DUK_INT_LEAST32_MAX INT_LEAST32_MAX -+#define DUK_UINT_FAST32_MIN 0 -+#define DUK_UINT_FAST32_MAX UINT_FAST32_MAX -+#define DUK_INT_FAST32_MIN INT_FAST32_MIN -+#define DUK_INT_FAST32_MAX INT_FAST32_MAX -+#define DUK_UINT64_MIN 0 -+#define DUK_UINT64_MAX UINT64_MAX -+#define DUK_INT64_MIN INT64_MIN -+#define DUK_INT64_MAX INT64_MAX -+#define DUK_UINT_LEAST64_MIN 0 -+#define DUK_UINT_LEAST64_MAX UINT_LEAST64_MAX -+#define DUK_INT_LEAST64_MIN INT_LEAST64_MIN -+#define DUK_INT_LEAST64_MAX INT_LEAST64_MAX -+#define DUK_UINT_FAST64_MIN 0 -+#define DUK_UINT_FAST64_MAX UINT_FAST64_MAX -+#define DUK_INT_FAST64_MIN INT_FAST64_MIN -+#define DUK_INT_FAST64_MAX INT_FAST64_MAX -+ -+#define DUK_UINTPTR_MIN 0 -+#define DUK_UINTPTR_MAX UINTPTR_MAX -+#define DUK_INTPTR_MIN INTPTR_MIN -+#define DUK_INTPTR_MAX INTPTR_MAX -+#undef DUK_UINTPTR_MAX_COMPUTED -+ -+#define DUK_UINTMAX_MIN 0 -+#define DUK_UINTMAX_MAX UINTMAX_MAX -+#define DUK_INTMAX_MIN INTMAX_MIN -+#define DUK_INTMAX_MAX INTMAX_MAX -+ -+#define DUK_SIZE_MIN 0 -+#define DUK_SIZE_MAX SIZE_MAX -+#undef DUK_SIZE_MAX_COMPUTED -diff --git a/dist/source/config/header-snippets/types_legacy.h.in b/dist/source/config/header-snippets/types_legacy.h.in -new file mode 100644 -index 0000000..45ffbd3 ---- /dev/null -+++ b/dist/source/config/header-snippets/types_legacy.h.in -@@ -0,0 +1,242 @@ -+/* When C99 types are not available, we use heuristic detection to get -+ * the basic 8, 16, 32, and (possibly) 64 bit types. The fast/least -+ * types are then assumed to be exactly the same for now: these could -+ * be improved per platform but C99 types are very often now available. -+ * 64-bit types are not available on all platforms; this is OK at least -+ * on 32-bit platforms. -+ * -+ * This detection code is necessarily a bit hacky and can provide typedefs -+ * and defines that won't work correctly on some exotic platform. -+ */ -+ -+#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \ -+ (defined(UCHAR_MAX) && (UCHAR_MAX == 255)) -+typedef unsigned char duk_uint8_t; -+typedef signed char duk_int8_t; -+#else -+#error cannot detect 8-bit type -+#endif -+ -+#if defined(USHRT_MAX) && (USHRT_MAX == 65535UL) -+typedef unsigned short duk_uint16_t; -+typedef signed short duk_int16_t; -+#elif defined(UINT_MAX) && (UINT_MAX == 65535UL) -+/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ -+typedef unsigned int duk_uint16_t; -+typedef signed int duk_int16_t; -+#else -+#error cannot detect 16-bit type -+#endif -+ -+#if defined(UINT_MAX) && (UINT_MAX == 4294967295UL) -+typedef unsigned int duk_uint32_t; -+typedef signed int duk_int32_t; -+#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295UL) -+/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */ -+typedef unsigned long duk_uint32_t; -+typedef signed long duk_int32_t; -+#else -+#error cannot detect 32-bit type -+#endif -+ -+/* 64-bit type detection is a bit tricky. -+ * -+ * ULLONG_MAX is a standard define. __LONG_LONG_MAX__ and __ULONG_LONG_MAX__ -+ * are used by at least GCC (even if system headers don't provide ULLONG_MAX). -+ * Some GCC variants may provide __LONG_LONG_MAX__ but not __ULONG_LONG_MAX__. -+ * -+ * ULL / LL constants are rejected / warned about by some compilers, even if -+ * the compiler has a 64-bit type and the compiler/system headers provide an -+ * unsupported constant (ULL/LL)! Try to avoid using ULL / LL constants. -+ * As a side effect we can only check that e.g. ULONG_MAX is larger than 32 -+ * bits but can't be sure it is exactly 64 bits. Self tests will catch such -+ * cases. -+ */ -+#undef DUK_F_HAVE_64BIT -+#if !defined(DUK_F_HAVE_64BIT) && defined(ULONG_MAX) -+#if (ULONG_MAX > 4294967295UL) -+#define DUK_F_HAVE_64BIT -+typedef unsigned long duk_uint64_t; -+typedef signed long duk_int64_t; -+#endif -+#endif -+#if !defined(DUK_F_HAVE_64BIT) && defined(ULLONG_MAX) -+#if (ULLONG_MAX > 4294967295UL) -+#define DUK_F_HAVE_64BIT -+typedef unsigned long long duk_uint64_t; -+typedef signed long long duk_int64_t; -+#endif -+#endif -+#if !defined(DUK_F_HAVE_64BIT) && defined(__ULONG_LONG_MAX__) -+#if (__ULONG_LONG_MAX__ > 4294967295UL) -+#define DUK_F_HAVE_64BIT -+typedef unsigned long long duk_uint64_t; -+typedef signed long long duk_int64_t; -+#endif -+#endif -+#if !defined(DUK_F_HAVE_64BIT) && defined(__LONG_LONG_MAX__) -+#if (__LONG_LONG_MAX__ > 2147483647L) -+#define DUK_F_HAVE_64BIT -+typedef unsigned long long duk_uint64_t; -+typedef signed long long duk_int64_t; -+#endif -+#endif -+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MINGW) -+#define DUK_F_HAVE_64BIT -+typedef unsigned long duk_uint64_t; -+typedef signed long duk_int64_t; -+#endif -+#if !defined(DUK_F_HAVE_64BIT) && defined(DUK_F_MSVC) -+#define DUK_F_HAVE_64BIT -+typedef unsigned __int64 duk_uint64_t; -+typedef signed __int64 duk_int64_t; -+#endif -+#if !defined(DUK_F_HAVE_64BIT) -+/* cannot detect 64-bit type, not always needed so don't error */ -+#endif -+ -+typedef duk_uint8_t duk_uint_least8_t; -+typedef duk_int8_t duk_int_least8_t; -+typedef duk_uint16_t duk_uint_least16_t; -+typedef duk_int16_t duk_int_least16_t; -+typedef duk_uint32_t duk_uint_least32_t; -+typedef duk_int32_t duk_int_least32_t; -+typedef duk_uint8_t duk_uint_fast8_t; -+typedef duk_int8_t duk_int_fast8_t; -+typedef duk_uint16_t duk_uint_fast16_t; -+typedef duk_int16_t duk_int_fast16_t; -+typedef duk_uint32_t duk_uint_fast32_t; -+typedef duk_int32_t duk_int_fast32_t; -+#if defined(DUK_F_HAVE_64BIT) -+typedef duk_uint64_t duk_uint_least64_t; -+typedef duk_int64_t duk_int_least64_t; -+typedef duk_uint64_t duk_uint_fast64_t; -+typedef duk_int64_t duk_int_fast64_t; -+#endif -+#if defined(DUK_F_HAVE_64BIT) -+typedef duk_uint64_t duk_uintmax_t; -+typedef duk_int64_t duk_intmax_t; -+#else -+typedef duk_uint32_t duk_uintmax_t; -+typedef duk_int32_t duk_intmax_t; -+#endif -+ -+/* Note: the funny looking computations for signed minimum 16-bit, 32-bit, and -+ * 64-bit values are intentional as the obvious forms (e.g. -0x80000000L) are -+ * -not- portable. See code-issues.txt for a detailed discussion. -+ */ -+#define DUK_UINT8_MIN 0UL -+#define DUK_UINT8_MAX 0xffUL -+#define DUK_INT8_MIN (-0x80L) -+#define DUK_INT8_MAX 0x7fL -+#define DUK_UINT_LEAST8_MIN 0UL -+#define DUK_UINT_LEAST8_MAX 0xffUL -+#define DUK_INT_LEAST8_MIN (-0x80L) -+#define DUK_INT_LEAST8_MAX 0x7fL -+#define DUK_UINT_FAST8_MIN 0UL -+#define DUK_UINT_FAST8_MAX 0xffUL -+#define DUK_INT_FAST8_MIN (-0x80L) -+#define DUK_INT_FAST8_MAX 0x7fL -+#define DUK_UINT16_MIN 0UL -+#define DUK_UINT16_MAX 0xffffUL -+#define DUK_INT16_MIN (-0x7fffL - 1L) -+#define DUK_INT16_MAX 0x7fffL -+#define DUK_UINT_LEAST16_MIN 0UL -+#define DUK_UINT_LEAST16_MAX 0xffffUL -+#define DUK_INT_LEAST16_MIN (-0x7fffL - 1L) -+#define DUK_INT_LEAST16_MAX 0x7fffL -+#define DUK_UINT_FAST16_MIN 0UL -+#define DUK_UINT_FAST16_MAX 0xffffUL -+#define DUK_INT_FAST16_MIN (-0x7fffL - 1L) -+#define DUK_INT_FAST16_MAX 0x7fffL -+#define DUK_UINT32_MIN 0UL -+#define DUK_UINT32_MAX 0xffffffffUL -+#define DUK_INT32_MIN (-0x7fffffffL - 1L) -+#define DUK_INT32_MAX 0x7fffffffL -+#define DUK_UINT_LEAST32_MIN 0UL -+#define DUK_UINT_LEAST32_MAX 0xffffffffUL -+#define DUK_INT_LEAST32_MIN (-0x7fffffffL - 1L) -+#define DUK_INT_LEAST32_MAX 0x7fffffffL -+#define DUK_UINT_FAST32_MIN 0UL -+#define DUK_UINT_FAST32_MAX 0xffffffffUL -+#define DUK_INT_FAST32_MIN (-0x7fffffffL - 1L) -+#define DUK_INT_FAST32_MAX 0x7fffffffL -+ -+/* 64-bit constants. Since LL / ULL constants are not always available, -+ * use computed values. These values can't be used in preprocessor -+ * comparisons; flag them as such. -+ */ -+#if defined(DUK_F_HAVE_64BIT) -+#define DUK_UINT64_MIN ((duk_uint64_t) 0) -+#define DUK_UINT64_MAX ((duk_uint64_t) -1) -+#define DUK_INT64_MIN ((duk_int64_t) (~(DUK_UINT64_MAX >> 1))) -+#define DUK_INT64_MAX ((duk_int64_t) (DUK_UINT64_MAX >> 1)) -+#define DUK_UINT_LEAST64_MIN DUK_UINT64_MIN -+#define DUK_UINT_LEAST64_MAX DUK_UINT64_MAX -+#define DUK_INT_LEAST64_MIN DUK_INT64_MIN -+#define DUK_INT_LEAST64_MAX DUK_INT64_MAX -+#define DUK_UINT_FAST64_MIN DUK_UINT64_MIN -+#define DUK_UINT_FAST64_MAX DUK_UINT64_MAX -+#define DUK_INT_FAST64_MIN DUK_INT64_MIN -+#define DUK_INT_FAST64_MAX DUK_INT64_MAX -+#define DUK_UINT64_MIN_COMPUTED -+#define DUK_UINT64_MAX_COMPUTED -+#define DUK_INT64_MIN_COMPUTED -+#define DUK_INT64_MAX_COMPUTED -+#define DUK_UINT_LEAST64_MIN_COMPUTED -+#define DUK_UINT_LEAST64_MAX_COMPUTED -+#define DUK_INT_LEAST64_MIN_COMPUTED -+#define DUK_INT_LEAST64_MAX_COMPUTED -+#define DUK_UINT_FAST64_MIN_COMPUTED -+#define DUK_UINT_FAST64_MAX_COMPUTED -+#define DUK_INT_FAST64_MIN_COMPUTED -+#define DUK_INT_FAST64_MAX_COMPUTED -+#endif -+ -+#if defined(DUK_F_HAVE_64BIT) -+#define DUK_UINTMAX_MIN DUK_UINT64_MIN -+#define DUK_UINTMAX_MAX DUK_UINT64_MAX -+#define DUK_INTMAX_MIN DUK_INT64_MIN -+#define DUK_INTMAX_MAX DUK_INT64_MAX -+#define DUK_UINTMAX_MIN_COMPUTED -+#define DUK_UINTMAX_MAX_COMPUTED -+#define DUK_INTMAX_MIN_COMPUTED -+#define DUK_INTMAX_MAX_COMPUTED -+#else -+#define DUK_UINTMAX_MIN 0UL -+#define DUK_UINTMAX_MAX 0xffffffffUL -+#define DUK_INTMAX_MIN (-0x7fffffffL - 1L) -+#define DUK_INTMAX_MAX 0x7fffffffL -+#endif -+ -+/* This detection is not very reliable. */ -+#if defined(DUK_F_32BIT_PTRS) -+typedef duk_int32_t duk_intptr_t; -+typedef duk_uint32_t duk_uintptr_t; -+#define DUK_UINTPTR_MIN DUK_UINT32_MIN -+#define DUK_UINTPTR_MAX DUK_UINT32_MAX -+#define DUK_INTPTR_MIN DUK_INT32_MIN -+#define DUK_INTPTR_MAX DUK_INT32_MAX -+#elif defined(DUK_F_64BIT_PTRS) && defined(DUK_F_HAVE_64BIT) -+typedef duk_int64_t duk_intptr_t; -+typedef duk_uint64_t duk_uintptr_t; -+#define DUK_UINTPTR_MIN DUK_UINT64_MIN -+#define DUK_UINTPTR_MAX DUK_UINT64_MAX -+#define DUK_INTPTR_MIN DUK_INT64_MIN -+#define DUK_INTPTR_MAX DUK_INT64_MAX -+#define DUK_UINTPTR_MIN_COMPUTED -+#define DUK_UINTPTR_MAX_COMPUTED -+#define DUK_INTPTR_MIN_COMPUTED -+#define DUK_INTPTR_MAX_COMPUTED -+#else -+#error cannot determine intptr type -+#endif -+ -+/* SIZE_MAX may be missing so use an approximate value for it. */ -+#undef DUK_SIZE_MAX_COMPUTED -+#if !defined(SIZE_MAX) -+#define DUK_SIZE_MAX_COMPUTED -+#define SIZE_MAX ((size_t) (-1)) -+#endif -+#define DUK_SIZE_MIN 0 -+#define DUK_SIZE_MAX SIZE_MAX -diff --git a/dist/source/config/helper-snippets/DUK_F_AIX.h.in b/dist/source/config/helper-snippets/DUK_F_AIX.h.in -new file mode 100644 -index 0000000..d026f18 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_AIX.h.in -@@ -0,0 +1,5 @@ -+/* AIX */ -+#if defined(_AIX) -+/* defined(__xlc__) || defined(__IBMC__): works but too wide */ -+#define DUK_F_AIX -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_AMIGAOS.h.in b/dist/source/config/helper-snippets/DUK_F_AMIGAOS.h.in -new file mode 100644 -index 0000000..6bdc5d6 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_AMIGAOS.h.in -@@ -0,0 +1,6 @@ -+/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must -+ * define 'AMIGA' manually when using VBCC. -+ */ -+#if defined(AMIGA) || defined(__amigaos__) -+#define DUK_F_AMIGAOS -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_ANDROID.h.in b/dist/source/config/helper-snippets/DUK_F_ANDROID.h.in -new file mode 100644 -index 0000000..5ebb645 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_ANDROID.h.in -@@ -0,0 +1,3 @@ -+#if defined(ANDROID) || defined(__ANDROID__) -+#define DUK_F_ANDROID -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_APPLE.h.in b/dist/source/config/helper-snippets/DUK_F_APPLE.h.in -new file mode 100644 -index 0000000..4a934ee ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_APPLE.h.in -@@ -0,0 +1,4 @@ -+/* Apple macOS, iOS, watchOS, tvOS, Darwin, etc */ -+#if defined(__APPLE__) -+#define DUK_F_APPLE -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_ARM.h.in b/dist/source/config/helper-snippets/DUK_F_ARM.h.in -new file mode 100644 -index 0000000..df84337 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_ARM.h.in -@@ -0,0 +1,9 @@ -+/* ARM */ -+#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) -+#define DUK_F_ARM -+#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__) || defined(_M_ARM64) || defined(__aarch64__) -+#define DUK_F_ARM64 -+#else -+#define DUK_F_ARM32 -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_BCC.h.in b/dist/source/config/helper-snippets/DUK_F_BCC.h.in -new file mode 100644 -index 0000000..f8442cb ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_BCC.h.in -@@ -0,0 +1,4 @@ -+/* BCC (Bruce's C compiler): this is a "torture target" for compilation */ -+#if defined(__BCC__) || defined(__BCC_VERSION__) -+#define DUK_F_BCC -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_BSD.h.in b/dist/source/config/helper-snippets/DUK_F_BSD.h.in -new file mode 100644 -index 0000000..b1577e6 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_BSD.h.in -@@ -0,0 +1,5 @@ -+/* BSD variant */ -+#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \ -+ defined(__bsdi__) || defined(__DragonFly__) -+#define DUK_F_BSD -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_C99.h.in b/dist/source/config/helper-snippets/DUK_F_C99.h.in -new file mode 100644 -index 0000000..bc44022 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_C99.h.in -@@ -0,0 +1,5 @@ -+/* C99 or above */ -+#undef DUK_F_C99 -+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -+#define DUK_F_C99 -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_CLANG.h.in b/dist/source/config/helper-snippets/DUK_F_CLANG.h.in -new file mode 100644 -index 0000000..33f7f65 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_CLANG.h.in -@@ -0,0 +1,4 @@ -+/* Clang */ -+#if defined(__clang__) -+#define DUK_F_CLANG -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_CPP.h.in b/dist/source/config/helper-snippets/DUK_F_CPP.h.in -new file mode 100644 -index 0000000..8489fc1 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_CPP.h.in -@@ -0,0 +1,5 @@ -+/* C++ */ -+#undef DUK_F_CPP -+#if defined(__cplusplus) -+#define DUK_F_CPP -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_CPP11.h.in b/dist/source/config/helper-snippets/DUK_F_CPP11.h.in -new file mode 100644 -index 0000000..015259a ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_CPP11.h.in -@@ -0,0 +1,5 @@ -+/* C++11 or above */ -+#undef DUK_F_CPP11 -+#if defined(__cplusplus) && (__cplusplus >= 201103L) -+#define DUK_F_CPP11 -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_CYGWIN.h.in b/dist/source/config/helper-snippets/DUK_F_CYGWIN.h.in -new file mode 100644 -index 0000000..9d631a7 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_CYGWIN.h.in -@@ -0,0 +1,4 @@ -+/* Cygwin */ -+#if defined(__CYGWIN__) -+#define DUK_F_CYGWIN -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_DURANGO.h.in b/dist/source/config/helper-snippets/DUK_F_DURANGO.h.in -new file mode 100644 -index 0000000..8e64e98 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_DURANGO.h.in -@@ -0,0 +1,4 @@ -+/* Durango (Xbox One) */ -+#if defined(_DURANGO) || defined(_XBOX_ONE) -+#define DUK_F_DURANGO -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_EMSCRIPTEN.h.in b/dist/source/config/helper-snippets/DUK_F_EMSCRIPTEN.h.in -new file mode 100644 -index 0000000..ba299cd ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_EMSCRIPTEN.h.in -@@ -0,0 +1,4 @@ -+/* Emscripten (provided explicitly by user), improve if possible */ -+#if defined(EMSCRIPTEN) -+#define DUK_F_EMSCRIPTEN -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_FLASHPLAYER.h.in b/dist/source/config/helper-snippets/DUK_F_FLASHPLAYER.h.in -new file mode 100644 -index 0000000..39060c1 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_FLASHPLAYER.h.in -@@ -0,0 +1,4 @@ -+/* Flash player (e.g. Crossbridge) */ -+#if defined(__FLASHPLAYER__) -+#define DUK_F_FLASHPLAYER -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_FREEBSD.h.in b/dist/source/config/helper-snippets/DUK_F_FREEBSD.h.in -new file mode 100644 -index 0000000..621b92e ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_FREEBSD.h.in -@@ -0,0 +1,4 @@ -+/* FreeBSD */ -+#if defined(__FreeBSD__) || defined(__FreeBSD) -+#define DUK_F_FREEBSD -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_GCC.h.in b/dist/source/config/helper-snippets/DUK_F_GCC.h.in -new file mode 100644 -index 0000000..ccb4ffb ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_GCC.h.in -@@ -0,0 +1,10 @@ -+/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */ -+#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG) -+#define DUK_F_GCC -+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -+/* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */ -+#define DUK_F_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__) -+#else -+#error cannot figure out gcc version -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_HPUX.h.in b/dist/source/config/helper-snippets/DUK_F_HPUX.h.in -new file mode 100644 -index 0000000..33531c6 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_HPUX.h.in -@@ -0,0 +1,7 @@ -+/* HPUX */ -+#if defined(__hpux) -+#define DUK_F_HPUX -+#if defined(__ia64) -+#define DUK_F_HPUX_ITANIUM -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_LINUX.h.in b/dist/source/config/helper-snippets/DUK_F_LINUX.h.in -new file mode 100644 -index 0000000..79ace6f ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_LINUX.h.in -@@ -0,0 +1,4 @@ -+/* Linux */ -+#if defined(__linux) || defined(__linux__) || defined(linux) -+#define DUK_F_LINUX -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_M68K.h.in b/dist/source/config/helper-snippets/DUK_F_M68K.h.in -new file mode 100644 -index 0000000..f377888 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_M68K.h.in -@@ -0,0 +1,6 @@ -+/* Motorola 68K. Not defined by VBCC, so user must define one of these -+ * manually when using VBCC. -+ */ -+#if defined(__m68k__) || defined(M68000) || defined(__MC68K__) -+#define DUK_F_M68K -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_MINGW.h.in b/dist/source/config/helper-snippets/DUK_F_MINGW.h.in -new file mode 100644 -index 0000000..8b8a16d ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_MINGW.h.in -@@ -0,0 +1,4 @@ -+/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */ -+#if defined(__MINGW32__) || defined(__MINGW64__) -+#define DUK_F_MINGW -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_MINT.h.in b/dist/source/config/helper-snippets/DUK_F_MINT.h.in -new file mode 100644 -index 0000000..ae269cd ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_MINT.h.in -@@ -0,0 +1,4 @@ -+/* Atari Mint */ -+#if defined(__MINT__) -+#define DUK_F_MINT -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_MIPS.h.in b/dist/source/config/helper-snippets/DUK_F_MIPS.h.in -new file mode 100644 -index 0000000..1d57239 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_MIPS.h.in -@@ -0,0 +1,14 @@ -+/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */ -+#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \ -+ defined(_R3000) || defined(_R4000) || defined(_R5900) || \ -+ defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \ -+ defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \ -+ defined(__mips) || defined(__MIPS__) -+#define DUK_F_MIPS -+#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \ -+ defined(__mips64__) || defined(__mips_n64) -+#define DUK_F_MIPS64 -+#else -+#define DUK_F_MIPS32 -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_MSVC.h.in b/dist/source/config/helper-snippets/DUK_F_MSVC.h.in -new file mode 100644 -index 0000000..2ddd894 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_MSVC.h.in -@@ -0,0 +1,15 @@ -+/* MSVC */ -+#if defined(_MSC_VER) -+/* MSVC preprocessor defines: http://msdn.microsoft.com/en-us/library/b0084kay.aspx -+ * _MSC_FULL_VER includes the build number, but it has at least two formats, see e.g. -+ * BOOST_MSVC_FULL_VER in http://www.boost.org/doc/libs/1_52_0/boost/config/compiler/visualc.hpp -+ */ -+#define DUK_F_MSVC -+#if defined(_MSC_FULL_VER) -+#if (_MSC_FULL_VER > 100000000) -+#define DUK_F_MSVC_FULL_VER _MSC_FULL_VER -+#else -+#define DUK_F_MSCV_FULL_VER (_MSC_FULL_VER * 10) -+#endif -+#endif -+#endif /* _MSC_VER */ -diff --git a/dist/source/config/helper-snippets/DUK_F_NETBSD.h.in b/dist/source/config/helper-snippets/DUK_F_NETBSD.h.in -new file mode 100644 -index 0000000..2705bc8 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_NETBSD.h.in -@@ -0,0 +1,4 @@ -+/* NetBSD */ -+#if defined(__NetBSD__) || defined(__NetBSD) -+#define DUK_F_NETBSD -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_NO_STDINT_H.h.in b/dist/source/config/helper-snippets/DUK_F_NO_STDINT_H.h.in -new file mode 100644 -index 0000000..47e16ef ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_NO_STDINT_H.h.in -@@ -0,0 +1,10 @@ -+/* stdint.h not available */ -+#if defined(DUK_F_WINDOWS) && defined(_MSC_VER) -+#if (_MSC_VER < 1700) -+/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */ -+#define DUK_F_NO_STDINT_H -+#endif -+#endif -+#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC)) -+#define DUK_F_NO_STDINT_H -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_OPENBSD.h.in b/dist/source/config/helper-snippets/DUK_F_OPENBSD.h.in -new file mode 100644 -index 0000000..e882b6c ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_OPENBSD.h.in -@@ -0,0 +1,4 @@ -+/* OpenBSD */ -+#if defined(__OpenBSD__) || defined(__OpenBSD) -+#define DUK_F_OPENBSD -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_ORBIS.h.in b/dist/source/config/helper-snippets/DUK_F_ORBIS.h.in -new file mode 100644 -index 0000000..717918e ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_ORBIS.h.in -@@ -0,0 +1,4 @@ -+/* Orbis (PS4) variant */ -+#if defined(DUK_F_FREEBSD) && defined(__ORBIS__) -+#define DUK_F_ORBIS -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_POSIX.h.in b/dist/source/config/helper-snippets/DUK_F_POSIX.h.in -new file mode 100644 -index 0000000..ea153c6 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_POSIX.h.in -@@ -0,0 +1,4 @@ -+/* POSIX */ -+#if defined(__posix) -+#define DUK_F_POSIX -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_PPC.h.in b/dist/source/config/helper-snippets/DUK_F_PPC.h.in -new file mode 100644 -index 0000000..b1ab82c ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_PPC.h.in -@@ -0,0 +1,9 @@ -+/* PowerPC */ -+#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__) -+#define DUK_F_PPC -+#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64) -+#define DUK_F_PPC64 -+#else -+#define DUK_F_PPC32 -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_QNX.h.in b/dist/source/config/helper-snippets/DUK_F_QNX.h.in -new file mode 100644 -index 0000000..9fe1d01 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_QNX.h.in -@@ -0,0 +1,4 @@ -+/* QNX */ -+#if defined(__QNX__) -+#define DUK_F_QNX -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_RISCV.h.in b/dist/source/config/helper-snippets/DUK_F_RISCV.h.in -new file mode 100644 -index 0000000..144215f ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_RISCV.h.in -@@ -0,0 +1,15 @@ -+/* RISC-V, https://github.com/riscv/riscv-toolchain-conventions#cc-preprocessor-definitions */ -+#if defined(__riscv) -+#define DUK_F_RISCV -+#if defined(__riscv_xlen) -+#if (__riscv_xlen == 32) -+#define DUK_F_RISCV32 -+#elif (__riscv_xlen == 64) -+#define DUK_F_RISCV64 -+#else -+#error __riscv_xlen has unsupported value (not 32 or 64) -+#endif -+#else -+#error __riscv defined without __riscv_xlen -+#endif -+#endif /* __riscv */ -diff --git a/dist/source/config/helper-snippets/DUK_F_SPARC.h.in b/dist/source/config/helper-snippets/DUK_F_SPARC.h.in -new file mode 100644 -index 0000000..37e1e70 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_SPARC.h.in -@@ -0,0 +1,9 @@ -+/* SPARC */ -+#if defined(sparc) || defined(__sparc) || defined(__sparc__) -+#define DUK_F_SPARC -+#if defined(__LP64__) || defined(_LP64) -+#define DUK_F_SPARC64 -+#else -+#define DUK_F_SPARC32 -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_SUN.h.in b/dist/source/config/helper-snippets/DUK_F_SUN.h.in -new file mode 100644 -index 0000000..9ae871d ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_SUN.h.in -@@ -0,0 +1,12 @@ -+/* illumos / Solaris */ -+#if defined(__sun) && defined(__SVR4) -+#define DUK_F_SUN -+#if defined(__SUNPRO_C) && (__SUNPRO_C < 0x550) -+#define DUK_F_OLD_SOLARIS -+/* Defines _ILP32 / _LP64 required by DUK_F_X86/DUK_F_X64. Platforms -+ * are processed before architectures, so this happens before the -+ * DUK_F_X86/DUK_F_X64 detection is emitted. -+ */ -+#include -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_SUPERH.h.in b/dist/source/config/helper-snippets/DUK_F_SUPERH.h.in -new file mode 100644 -index 0000000..cd9eca5 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_SUPERH.h.in -@@ -0,0 +1,9 @@ -+/* SuperH */ -+#if defined(__sh__) || \ -+ defined(__sh1__) || defined(__SH1__) || \ -+ defined(__sh2__) || defined(__SH2__) || \ -+ defined(__sh3__) || defined(__SH3__) || \ -+ defined(__sh4__) || defined(__SH4__) || \ -+ defined(__sh5__) || defined(__SH5__) -+#define DUK_F_SUPERH -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_TINSPIRE.h.in b/dist/source/config/helper-snippets/DUK_F_TINSPIRE.h.in -new file mode 100644 -index 0000000..7451979 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_TINSPIRE.h.in -@@ -0,0 +1,4 @@ -+/* TI-Nspire (using Ndless) */ -+#if defined(_TINSPIRE) -+#define DUK_F_TINSPIRE -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_TINYC.h.in b/dist/source/config/helper-snippets/DUK_F_TINYC.h.in -new file mode 100644 -index 0000000..43a0cff ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_TINYC.h.in -@@ -0,0 +1,5 @@ -+/* TinyC */ -+#if defined(__TINYC__) -+/* http://bellard.org/tcc/tcc-doc.html#SEC9 */ -+#define DUK_F_TINYC -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_TOS.h.in b/dist/source/config/helper-snippets/DUK_F_TOS.h.in -new file mode 100644 -index 0000000..fcc296d ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_TOS.h.in -@@ -0,0 +1,6 @@ -+/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC -+ * apparently, so to use with VBCC user must define __TOS__ manually. -+ */ -+#if defined(__TOS__) -+#define DUK_F_TOS -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_UCLIBC.h.in b/dist/source/config/helper-snippets/DUK_F_UCLIBC.h.in -new file mode 100644 -index 0000000..7706962 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_UCLIBC.h.in -@@ -0,0 +1,4 @@ -+/* uclibc */ -+#if defined(__UCLIBC__) -+#define DUK_F_UCLIBC -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_ULL_CONSTS.h.in b/dist/source/config/helper-snippets/DUK_F_ULL_CONSTS.h.in -new file mode 100644 -index 0000000..188f628 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_ULL_CONSTS.h.in -@@ -0,0 +1,9 @@ -+/* ULL / LL preprocessor constants should be avoided because they're not -+ * always available. With suitable options, some compilers will support -+ * 64-bit integer types but won't support ULL / LL preprocessor constants. -+ * Assume C99/C++11 environments have these. However, BCC is nominally -+ * C99 but doesn't support these constants. -+ */ -+#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && !defined(DUK_F_BCC) -+#define DUK_F_ULL_CONSTS -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_UNIX.h.in b/dist/source/config/helper-snippets/DUK_F_UNIX.h.in -new file mode 100644 -index 0000000..ab15b35 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_UNIX.h.in -@@ -0,0 +1,5 @@ -+/* Generic Unix (includes Cygwin) */ -+#if defined(__unix) || defined(__unix__) || defined(unix) || \ -+ defined(DUK_F_LINUX) || defined(DUK_F_BSD) -+#define DUK_F_UNIX -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_VBCC.h.in b/dist/source/config/helper-snippets/DUK_F_VBCC.h.in -new file mode 100644 -index 0000000..f50e481 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_VBCC.h.in -@@ -0,0 +1,4 @@ -+/* VBCC */ -+#if defined(__VBCC__) -+#define DUK_F_VBCC -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_WINDOWS.h.in b/dist/source/config/helper-snippets/DUK_F_WINDOWS.h.in -new file mode 100644 -index 0000000..20aa769 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_WINDOWS.h.in -@@ -0,0 +1,10 @@ -+/* Windows, both 32-bit and 64-bit */ -+#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \ -+ defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) -+#define DUK_F_WINDOWS -+#if defined(_WIN64) || defined(WIN64) -+#define DUK_F_WIN64 -+#else -+#define DUK_F_WIN32 -+#endif -+#endif -diff --git a/dist/source/config/helper-snippets/DUK_F_X86.h.in b/dist/source/config/helper-snippets/DUK_F_X86.h.in -new file mode 100644 -index 0000000..0df3360 ---- /dev/null -+++ b/dist/source/config/helper-snippets/DUK_F_X86.h.in -@@ -0,0 +1,26 @@ -+/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers), -+ * define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32. -+ * https://sites.google.com/site/x32abi/ -+ * -+ * With DUK_F_OLD_SOLARIS the header must be included -+ * before this. -+ */ -+#if defined(__amd64__) || defined(__amd64) || \ -+ defined(__x86_64__) || defined(__x86_64) || \ -+ defined(_M_X64) || defined(_M_AMD64) -+#if defined(__ILP32__) || defined(_ILP32) -+#define DUK_F_X32 -+#else -+#define DUK_F_X64 -+#endif -+#elif defined(i386) || defined(__i386) || defined(__i386__) || \ -+ defined(__i486__) || defined(__i586__) || defined(__i686__) || \ -+ defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \ -+ defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) -+#if defined(__LP64__) || defined(_LP64) -+/* This should not really happen, but would indicate x64. */ -+#define DUK_F_X64 -+#else -+#define DUK_F_X86 -+#endif -+#endif -diff --git a/dist/source/config/platforms.yaml b/dist/source/config/platforms.yaml -new file mode 100644 -index 0000000..d8a39b4 ---- /dev/null -+++ b/dist/source/config/platforms.yaml -@@ -0,0 +1,89 @@ -+# Platform metadata. -+ -+autodetect: -+ # Platforms for autodetect header. Order matters because some defines -+ # overlap, so rules select for more specific define first. -+ - -+ name: macOS, iOS, watchOS, tvOS, Darwin, etc -+ check: DUK_F_APPLE -+ include: platform_apple.h.in -+ - -+ name: Orbis -+ check: DUK_F_ORBIS -+ include: platform_orbis.h.in -+ - -+ name: OpenBSD -+ check: DUK_F_OPENBSD -+ include: platform_openbsd.h.in -+ - -+ name: Generic BSD -+ check: DUK_F_BSD -+ include: platform_genericbsd.h.in -+ - -+ name: Atari ST TOS -+ check: DUK_F_TOS -+ include: platform_tos.h.in -+ - -+ name: AmigaOS -+ check: DUK_F_AMIGAOS -+ include: platform_amigaos.h.in -+ - -+ name: Durango (XboxOne) -+ check: DUK_F_DURANGO -+ include: platform_durango.h.in -+ - -+ name: Windows -+ check: DUK_F_WINDOWS -+ include: platform_windows.h.in -+ - -+ name: Flashplayer (Crossbridge) -+ check: DUK_F_FLASHPLAYER -+ include: platform_flashplayer.h.in -+ - -+ name: QNX -+ check: DUK_F_QNX -+ include: platform_qnx.h.in -+ - -+ name: TI-Nspire -+ check: DUK_F_TINSPIRE -+ include: platform_tinspire.h.in -+ - -+ name: Emscripten -+ check: DUK_F_EMSCRIPTEN -+ include: platform_emscripten.h.in -+ - -+ name: Android -+ check: DUK_F_ANDROID -+ include: platform_android.h.in -+ - -+ name: Linux -+ check: DUK_F_LINUX -+ include: platform_linux.h.in -+ - -+ name: Solaris -+ check: DUK_F_SUN -+ include: platform_solaris.h.in -+ - -+ name: AIX -+ check: DUK_F_AIX -+ include: platform_aix.h.in -+ - -+ name: HPUX -+ check: DUK_F_HPUX -+ include: platform_hpux.h.in -+ - -+ name: Generic POSIX -+ check: DUK_F_POSIX -+ include: platform_posix.h.in -+ - -+ name: Cygwin -+ check: DUK_F_CYGWIN -+ include: platform_cygwin.h.in -+ - -+ name: Generic UNIX -+ check: DUK_F_UNIX -+ include: platform_genericunix.h.in -+ - -+ name: Generic fallback -+ check: null -+ include: platform_generic.h.in # if nothing else -diff --git a/dist/source/config/platforms/platform_aix.h.in b/dist/source/config/platforms/platform_aix.h.in -new file mode 100644 -index 0000000..328f45c ---- /dev/null -+++ b/dist/source/config/platforms/platform_aix.h.in -@@ -0,0 +1,12 @@ -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 3 -+#endif -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "aix" -diff --git a/dist/source/config/platforms/platform_amigaos.h.in b/dist/source/config/platforms/platform_amigaos.h.in -new file mode 100644 -index 0000000..d71192e ---- /dev/null -+++ b/dist/source/config/platforms/platform_amigaos.h.in -@@ -0,0 +1,26 @@ -+#if defined(DUK_F_M68K) -+/* AmigaOS on M68k */ -+#define DUK_USE_DATE_NOW_TIME -+#define DUK_USE_DATE_TZO_GMTIME -+/* no parsing (not an error) */ -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#elif defined(DUK_F_PPC) -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#if !defined(UINTPTR_MAX) -+#define UINTPTR_MAX UINT_MAX -+#endif -+#else -+#error AmigaOS but not M68K/PPC, not supported now -+#endif -+ -+#define DUK_USE_OS_STRING "amigaos" -+ -+/* AmigaOS on M68K or PPC is always big endian. */ -+#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC)) -+#define DUK_USE_BYTEORDER 3 -+#endif -diff --git a/dist/source/config/platforms/platform_android.h.in b/dist/source/config/platforms/platform_android.h.in -new file mode 100644 -index 0000000..dc12cc8 ---- /dev/null -+++ b/dist/source/config/platforms/platform_android.h.in -@@ -0,0 +1,33 @@ -+#if defined(DUK_COMPILING_DUKTAPE) -+#if !defined(_POSIX_C_SOURCE) -+#define _POSIX_C_SOURCE 200809L -+#endif -+#if !defined(_GNU_SOURCE) -+#define _GNU_SOURCE /* e.g. getdate_r */ -+#endif -+#if !defined(_XOPEN_SOURCE) -+#define _XOPEN_SOURCE /* e.g. strptime */ -+#endif -+#endif /* DUK_COMPILING_DUKTAPE */ -+ -+#include -+#if defined(DUK_F_BCC) -+/* no endian.h or stdint.h */ -+#else -+#include -+#include -+#endif /* DUK_F_BCC */ -+#include -+#include -+#include -+ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+ -+#if 0 /* XXX: safe condition? */ -+#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME -+#endif -+ -+#define DUK_USE_OS_STRING "android" -diff --git a/dist/source/config/platforms/platform_apple.h.in b/dist/source/config/platforms/platform_apple.h.in -new file mode 100644 -index 0000000..e467604 ---- /dev/null -+++ b/dist/source/config/platforms/platform_apple.h.in -@@ -0,0 +1,49 @@ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+#include -+ -+/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */ -+/* https://stackoverflow.com/questions/12132933/preprocessor-macro-for-os-x-targets */ -+/* Some of the combinations below probably don't actually exist -+ * (like macOS simulator) but include them for completeness. -+ */ -+#if TARGET_OS_SIMULATOR && TARGET_OS_MACCATALYST -+#define DUK_USE_OS_STRING "catalyst-sim" -+#elif TARGET_OS_SIMULATOR && TARGET_OS_BRIDGE -+#define DUK_USE_OS_STRING "bridgeos-sim" -+#elif TARGET_OS_SIMULATOR && TARGET_OS_WATCH -+#define DUK_USE_OS_STRING "watchos-sim" -+#elif TARGET_OS_SIMULATOR && TARGET_OS_TV -+#define DUK_USE_OS_STRING "tvos-sim" -+#elif TARGET_OS_SIMULATOR && TARGET_OS_IOS -+#define DUK_USE_OS_STRING "ios-sim" -+#elif TARGET_IPHONE_SIMULATOR && TARGET_OS_IOS /* deprecated */ -+#define DUK_USE_OS_STRING "ios-sim" -+#elif TARGET_OS_SIMULATOR && TARGET_OS_MAC -+#define DUK_USE_OS_STRING "macos-sim" -+#elif TARGET_OS_MACCATALYST -+#define DUK_USE_OS_STRING "catalyst" -+#elif TARGET_OS_BRIDGE -+#define DUK_USE_OS_STRING "bridgeos" -+#elif TARGET_OS_WATCH -+#define DUK_USE_OS_STRING "watchos" -+#elif TARGET_OS_TV -+#define DUK_USE_OS_STRING "tvos" -+#elif TARGET_OS_IOS -+#define DUK_USE_OS_STRING "ios" -+#elif TARGET_OS_MAC -+#define DUK_USE_OS_STRING "macos" -+#else -+#define DUK_USE_OS_STRING "osx-unknown" -+#endif -+ -+/* Use _setjmp() on Apple by default, see GH-55. */ -+#define DUK_JMPBUF_TYPE jmp_buf -+#define DUK_SETJMP(jb) _setjmp((jb)) -+#define DUK_LONGJMP(jb) _longjmp((jb), 1) -diff --git a/dist/source/config/platforms/platform_cygwin.h.in b/dist/source/config/platforms/platform_cygwin.h.in -new file mode 100644 -index 0000000..cfe458b ---- /dev/null -+++ b/dist/source/config/platforms/platform_cygwin.h.in -@@ -0,0 +1,15 @@ -+/* don't use strptime() for now */ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+#include -+ -+#define DUK_JMPBUF_TYPE jmp_buf -+#define DUK_SETJMP(jb) _setjmp((jb)) -+#define DUK_LONGJMP(jb) _longjmp((jb), 1) -+ -+#define DUK_USE_OS_STRING "windows" -diff --git a/dist/source/config/platforms/platform_durango.h.in b/dist/source/config/platforms/platform_durango.h.in -new file mode 100644 -index 0000000..36326d8 ---- /dev/null -+++ b/dist/source/config/platforms/platform_durango.h.in -@@ -0,0 +1,32 @@ -+/* Durango = XboxOne -+ * Configuration is nearly identical to Windows, except for -+ * DUK_USE_DATE_TZO_WINDOWS. -+ */ -+ -+/* Initial fix: disable secure CRT related warnings when compiling Duktape -+ * itself (must be defined before including Windows headers). Don't define -+ * for user code including duktape.h. -+ */ -+#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) -+#define _CRT_SECURE_NO_WARNINGS -+#endif -+ -+/* MSVC does not have sys/param.h */ -+#define DUK_USE_DATE_NOW_WINDOWS -+#define DUK_USE_DATE_TZO_WINDOWS_NO_DST -+/* Note: PRS and FMT are intentionally left undefined for now. This means -+ * there is no platform specific date parsing/formatting but there is still -+ * the ISO 8601 standard format. -+ */ -+#if defined(DUK_COMPILING_DUKTAPE) -+/* Only include when compiling Duktape to avoid polluting application build -+ * with a lot of unnecessary defines. -+ */ -+#include -+#endif -+ -+#define DUK_USE_OS_STRING "durango" -+ -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 1 -+#endif -diff --git a/dist/source/config/platforms/platform_emscripten.h.in b/dist/source/config/platforms/platform_emscripten.h.in -new file mode 100644 -index 0000000..afc559d ---- /dev/null -+++ b/dist/source/config/platforms/platform_emscripten.h.in -@@ -0,0 +1,29 @@ -+#if defined(DUK_COMPILING_DUKTAPE) -+#if !defined(_POSIX_C_SOURCE) -+#define _POSIX_C_SOURCE 200809L -+#endif -+#if !defined(_GNU_SOURCE) -+#define _GNU_SOURCE /* e.g. getdate_r */ -+#endif -+#if !defined(_XOPEN_SOURCE) -+#define _XOPEN_SOURCE /* e.g. strptime */ -+#endif -+#endif /* DUK_COMPILING_DUKTAPE */ -+ -+#include -+#if defined(DUK_F_BCC) -+/* no endian.h */ -+#else -+#include -+#endif /* DUK_F_BCC */ -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+ -+#define DUK_USE_OS_STRING "emscripten" -diff --git a/dist/source/config/platforms/platform_flashplayer.h.in b/dist/source/config/platforms/platform_flashplayer.h.in -new file mode 100644 -index 0000000..fa7f6f6 ---- /dev/null -+++ b/dist/source/config/platforms/platform_flashplayer.h.in -@@ -0,0 +1,14 @@ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "flashplayer" -+ -+#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER) -+#define DUK_USE_BYTEORDER 1 -+#endif -diff --git a/dist/source/config/platforms/platform_generic.h.in b/dist/source/config/platforms/platform_generic.h.in -new file mode 100644 -index 0000000..24b552f ---- /dev/null -+++ b/dist/source/config/platforms/platform_generic.h.in -@@ -0,0 +1,18 @@ -+/* The most portable current time provider is time(), but it only has a -+ * one second resolution. -+ */ -+#define DUK_USE_DATE_NOW_TIME -+ -+/* The most portable way to figure out local time offset is gmtime(), -+ * but it's not thread safe so use with caution. -+ */ -+#define DUK_USE_DATE_TZO_GMTIME -+ -+/* Avoid custom date parsing and formatting for portability. */ -+#undef DUK_USE_DATE_PRS_STRPTIME -+#undef DUK_USE_DATE_FMT_STRFTIME -+ -+/* Rely on C89 headers only; time.h must be here. */ -+#include -+ -+#define DUK_USE_OS_STRING "unknown" -diff --git a/dist/source/config/platforms/platform_genericbsd.h.in b/dist/source/config/platforms/platform_genericbsd.h.in -new file mode 100644 -index 0000000..494f7b1 ---- /dev/null -+++ b/dist/source/config/platforms/platform_genericbsd.h.in -@@ -0,0 +1,11 @@ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "bsd" -diff --git a/dist/source/config/platforms/platform_genericunix.h.in b/dist/source/config/platforms/platform_genericunix.h.in -new file mode 100644 -index 0000000..ff3d4e3 ---- /dev/null -+++ b/dist/source/config/platforms/platform_genericunix.h.in -@@ -0,0 +1,7 @@ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#define DUK_USE_OS_STRING "unknown" -diff --git a/dist/source/config/platforms/platform_hpux.h.in b/dist/source/config/platforms/platform_hpux.h.in -new file mode 100644 -index 0000000..dac6e19 ---- /dev/null -+++ b/dist/source/config/platforms/platform_hpux.h.in -@@ -0,0 +1,13 @@ -+#define DUK_F_NO_STDINT_H -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 3 -+#endif -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "hpux" -diff --git a/dist/source/config/platforms/platform_linux.h.in b/dist/source/config/platforms/platform_linux.h.in -new file mode 100644 -index 0000000..cc3a69c ---- /dev/null -+++ b/dist/source/config/platforms/platform_linux.h.in -@@ -0,0 +1,33 @@ -+#if defined(DUK_COMPILING_DUKTAPE) -+#if !defined(_POSIX_C_SOURCE) -+#define _POSIX_C_SOURCE 200809L -+#endif -+#if !defined(_GNU_SOURCE) -+#define _GNU_SOURCE /* e.g. getdate_r */ -+#endif -+#if !defined(_XOPEN_SOURCE) -+#define _XOPEN_SOURCE /* e.g. strptime */ -+#endif -+#endif /* DUK_COMPILING_DUKTAPE */ -+ -+#include -+#if defined(DUK_F_BCC) -+/* no endian.h or stdint.h */ -+#else -+#include -+#include -+#endif /* DUK_F_BCC */ -+#include -+#include -+#include -+ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+ -+#if 0 /* XXX: safe condition? */ -+#define DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME -+#endif -+ -+#define DUK_USE_OS_STRING "linux" -diff --git a/dist/source/config/platforms/platform_openbsd.h.in b/dist/source/config/platforms/platform_openbsd.h.in -new file mode 100644 -index 0000000..f4b4977 ---- /dev/null -+++ b/dist/source/config/platforms/platform_openbsd.h.in -@@ -0,0 +1,12 @@ -+/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "openbsd" -diff --git a/dist/source/config/platforms/platform_orbis.h.in b/dist/source/config/platforms/platform_orbis.h.in -new file mode 100644 -index 0000000..684ebfd ---- /dev/null -+++ b/dist/source/config/platforms/platform_orbis.h.in -@@ -0,0 +1,12 @@ -+/* Orbis = PS4 */ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_S -+/* no parsing (not an error) */ -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "orbis" -diff --git a/dist/source/config/platforms/platform_posix.h.in b/dist/source/config/platforms/platform_posix.h.in -new file mode 100644 -index 0000000..fa42b1b ---- /dev/null -+++ b/dist/source/config/platforms/platform_posix.h.in -@@ -0,0 +1,11 @@ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "posix" -diff --git a/dist/source/config/platforms/platform_qnx.h.in b/dist/source/config/platforms/platform_qnx.h.in -new file mode 100644 -index 0000000..c4e2ee2 ---- /dev/null -+++ b/dist/source/config/platforms/platform_qnx.h.in -@@ -0,0 +1,16 @@ -+#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE) -+/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */ -+#define _XOPEN_SOURCE 600 -+#define _POSIX_C_SOURCE 200112L -+#endif -+ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "qnx" -diff --git a/dist/source/config/platforms/platform_solaris.h.in b/dist/source/config/platforms/platform_solaris.h.in -new file mode 100644 -index 0000000..b49fa2f ---- /dev/null -+++ b/dist/source/config/platforms/platform_solaris.h.in -@@ -0,0 +1,21 @@ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+ -+#include -+#if defined(DUK_F_OLD_SOLARIS) -+/* Old Solaris with no endian.h, stdint.h */ -+#define DUK_F_NO_STDINT_H -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 3 -+#endif -+#else /* DUK_F_OLD_SOLARIS */ -+#include -+#endif /* DUK_F_OLD_SOLARIS */ -+ -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "solaris" -diff --git a/dist/source/config/platforms/platform_tinspire.h.in b/dist/source/config/platforms/platform_tinspire.h.in -new file mode 100644 -index 0000000..6c54267 ---- /dev/null -+++ b/dist/source/config/platforms/platform_tinspire.h.in -@@ -0,0 +1,14 @@ -+#if defined(DUK_COMPILING_DUKTAPE) && !defined(_XOPEN_SOURCE) -+#define _XOPEN_SOURCE /* e.g. strptime */ -+#endif -+ -+#define DUK_USE_DATE_NOW_GETTIMEOFDAY -+#define DUK_USE_DATE_TZO_GMTIME_R -+#define DUK_USE_DATE_PRS_STRPTIME -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+#include -+#include -+#include -+ -+#define DUK_USE_OS_STRING "tinspire" -diff --git a/dist/source/config/platforms/platform_tos.h.in b/dist/source/config/platforms/platform_tos.h.in -new file mode 100644 -index 0000000..8c810e7 ---- /dev/null -+++ b/dist/source/config/platforms/platform_tos.h.in -@@ -0,0 +1,12 @@ -+#define DUK_USE_DATE_NOW_TIME -+#define DUK_USE_DATE_TZO_GMTIME -+/* no parsing (not an error) */ -+#define DUK_USE_DATE_FMT_STRFTIME -+#include -+ -+#define DUK_USE_OS_STRING "tos" -+ -+/* TOS on M68K is always big endian. */ -+#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K) -+#define DUK_USE_BYTEORDER 3 -+#endif -diff --git a/dist/source/config/platforms/platform_windows.h.in b/dist/source/config/platforms/platform_windows.h.in -new file mode 100644 -index 0000000..9e6fcf9 ---- /dev/null -+++ b/dist/source/config/platforms/platform_windows.h.in -@@ -0,0 +1,59 @@ -+/* Windows version can't obviously be determined at compile time, -+ * but _WIN32_WINNT indicates the minimum version targeted: -+ * - https://msdn.microsoft.com/en-us/library/6sehtctf.aspx -+ */ -+ -+/* Initial fix: disable secure CRT related warnings when compiling Duktape -+ * itself (must be defined before including Windows headers). Don't define -+ * for user code including duktape.h. -+ */ -+#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS) -+#define _CRT_SECURE_NO_WARNINGS -+#endif -+ -+/* Windows 32-bit and 64-bit are currently the same. */ -+/* MSVC does not have sys/param.h */ -+ -+#if defined(DUK_COMPILING_DUKTAPE) -+/* Only include when compiling Duktape to avoid polluting application build -+ * with a lot of unnecessary defines. -+ */ -+#include -+#endif -+ -+/* GetSystemTimePreciseAsFileTime() available from Windows 8: -+ * https://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=vs.85).aspx -+ */ -+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) || defined(DUK_USE_DATE_NOW_WINDOWS) -+/* User forced provider. */ -+#else -+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602) -+#define DUK_USE_DATE_NOW_WINDOWS_SUBMS -+#else -+#define DUK_USE_DATE_NOW_WINDOWS -+#endif -+#endif -+ -+#define DUK_USE_DATE_TZO_WINDOWS -+ -+/* Note: PRS and FMT are intentionally left undefined for now. This means -+ * there is no platform specific date parsing/formatting but there is still -+ * the ISO 8601 standard format. -+ */ -+ -+/* QueryPerformanceCounter() may go backwards in Windows XP, so enable for -+ * Vista and later: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions -+ */ -+#if !defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) && \ -+ defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) -+#define DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC -+#endif -+ -+#define DUK_USE_OS_STRING "windows" -+ -+/* On Windows, assume we're little endian. Even Itanium which has a -+ * configurable endianness runs little endian in Windows. -+ */ -+#if !defined(DUK_USE_BYTEORDER) -+#define DUK_USE_BYTEORDER 1 -+#endif -diff --git a/dist/source/config/tags.yaml b/dist/source/config/tags.yaml -new file mode 100644 -index 0000000..fbd6c83 ---- /dev/null -+++ b/dist/source/config/tags.yaml -@@ -0,0 +1,105 @@ -+# Properties for each tag: -+# -+# - title: title to use in header files -+# -+ -+ecmascript: -+ title: ECMAScript Edition 5 (ES5) options -+ -+ecmascript2015: -+ title: ECMAScript 2015 (ES6) options -+ -+ecmascript2016: -+ title: ECMAScript 2016 (ES7) options -+ -+ecmascript2017: -+ title: ECMAScript 2017 (ES8) options -+ -+ecmascript2018: -+ title: ECMAScript 2018 (ES9) options -+ -+duktape: -+ title: Duktape specific options -+ -+compliance: -+ title: Compliance related options -+ -+debugger: -+ title: Debugger options -+ -+debug: -+ title: Debug options -+ -+execution: -+ title: Execution options -+ -+sandbox: -+ title: Sandboxing options -+ -+performance: -+ title: Performance options -+ -+portability: -+ title: Platform and portability options -+ -+memory: -+ title: Memory management options -+ -+lowmemory: -+ title: Low memory options -+ -+gc: -+ title: Garbage collection options -+ -+misc: -+ title: Miscellaneous options -+ -+io: -+ title: I/O options -+ -+development: -+ title: Developer-only options -+ description: > -+ Developer options which are not intended for end users and are not -+ part of semantic versioning guarantees (e.g. torture options). -+ -+legacy: -+ title: Backwards compatibility options -+ description: > -+ Options for providing backwards compatible behavior. -+ -+date: -+ title: Date handling options -+ -+experimental: -+ title: Experimental options -+ -+api: -+ title: API options -+ -+fastpath: -+ title: Fast path performance options -+ -+cstackdepth: -+ title: C stack depth -+ -+torture: -+ title: Development time torture options -+ description: > -+ Development time options to stress test corner case handling by e.g. -+ causing a garbage collection on every allocation. -+ -+fuzzing: -+ title: Fuzzing -+ -+cbor: -+ title: CBOR -+ -+codec: -+ title: Codecs -+ -+encoding-api: -+ title: WHATWG Encoding API -+ -+performance-api: -+ title: Performance API (High Resolution Time) -diff --git a/dist/source/debugger/Makefile b/dist/source/debugger/Makefile -new file mode 100644 -index 0000000..f142c25 ---- /dev/null -+++ b/dist/source/debugger/Makefile -@@ -0,0 +1,101 @@ -+NODE:=$(shell { command -v nodejs || command -v node; } 2>/dev/null) -+DUKLUV:=$(shell command -v dukluv 2>/dev/null) -+ -+# Try to get a useful default --source-dirs which works both in the Duktape -+# repo and in the distributable. We don't want to add '..' because it would -+# scan a lot of undesired files in the Duktape repo (e.g. test262 testcases). -+ifeq ($(wildcard ../tests/ecmascript/*.js),) -+SOURCEDIRS:=../ -+else -+SOURCEDIRS:=../tests/ecmascript -+endif -+ -+.PHONY: all -+all: run -+ -+.PHONY: run -+run: node_modules static/socket.io-1.2.0.js static/jquery-1.11.1.min.js static/reset.css static/jquery-ui.min.js static/jquery-ui.min.css static/images -+ "$(NODE)" duk_debug.js --source-dirs=$(SOURCEDIRS) -+ -+rundebug: node_modules static/socket.io-1.2.0.js static/jquery-1.11.1.min.js static/reset.css static/jquery-ui.min.js static/jquery-ui.min.css static/images -+ "$(NODE)" duk_debug.js --source-dirs=$(SOURCEDIRS) --verbose --log-messages /tmp/dukdebug-messages --dump-debug-pretty /tmp/dukdebug-pretty -+ -+.PHONY: runproxynodejs -+runproxynodejs: node_modules static/socket.io-1.2.0.js static/jquery-1.11.1.min.js static/reset.css static/jquery-ui.min.js static/jquery-ui.min.css static/images -+ @echo "Running Node.js based debug proxy" -+ "$(NODE)" duk_debug.js --json-proxy -+ -+.PHONY: runproxydukluv -+runproxydukluv: duk_debug_meta.json -+ @echo "Running Dukluv based debug proxy (you may need to edit DUKLUV in the Makefile)" -+ "$(DUKLUV)" duk_debug_proxy.js --log-level 2 --metadata duk_debug_meta.json --readable-numbers -+ -+.PHONY: runproxy -+runproxy: runproxydukluv -+ -+.PHONY: clean -+clean: -+ @rm -f static/socket.io-1.2.0.js -+ @rm -f static/jquery-1.11.1.min.js -+ @rm -f static/jquery.syntaxhighlighter.min.js -+ @rm -f static/jquery.snippet.min.js -+ @rm -f static/jquery.snippet.min.css -+ @rm -f static/prefixfree.min.js -+ @rm -f static/reset.css -+ @rm -f static/jquery-ui.min.js -+ @rm -f static/jquery-ui.min.css -+ @rm -rf static/images -+ @rm -f jquery-ui-1.11.2.zip -+ @rm -rf jquery-ui-1.11.2 -+ @rm -rf node_modules -+ @rm -f duk_debug_meta.json -+ -+node_modules: -+ npm install -+ -+duk_debug_meta.json: -+ python2 ../tools/merge_debug_meta.py --output $@ \ -+ --class-names duk_classnames.yaml \ -+ --opcodes duk_opcodes.yaml \ -+ --debug-commands duk_debugcommands.yaml \ -+ --debug-errors duk_debugerrors.yaml -+ -+static/socket.io-1.2.0.js: -+ wget -O $@ http://cdn.socket.io/socket.io-1.2.0.js -+ -+static/jquery-1.11.1.min.js: -+ wget -O $@ http://code.jquery.com/jquery-1.11.1.min.js -+ -+# http://balupton.github.io/jquery-syntaxhighlighter/demo/ -+static/jquery.syntaxhighlighter.min.js: -+ wget -O $@ http://balupton.github.com/jquery-syntaxhighlighter/scripts/jquery.syntaxhighlighter.min.js -+ -+# http://steamdev.com/snippet/ -+static/jquery.snippet.min.js: -+ wget -O $@ http://steamdev.com/snippet/js/jquery.snippet.min.js -+static/jquery.snippet.min.css: -+ wget -O $@ http://steamdev.com/snippet/css/jquery.snippet.min.css -+ -+# http://prismjs.com/ -+# http://prismjs.com/plugins/line-highlight/ -+# -+# XXX: prism download manually? -+ -+# https://raw.github.com/LeaVerou/prefixfree/gh-pages/prefixfree.min.js -+static/prefixfree.min.js: -+ wget -O $@ https://raw.github.com/LeaVerou/prefixfree/gh-pages/prefixfree.min.js -+ -+# http://meyerweb.com/eric/tools/css/reset/ -+static/reset.css: -+ wget -O $@ http://meyerweb.com/eric/tools/css/reset/reset.css -+ -+jquery-ui-1.11.2.zip: -+ wget -O $@ http://jqueryui.com/resources/download/jquery-ui-1.11.2.zip -+jquery-ui-1.11.2: jquery-ui-1.11.2.zip -+ unzip $< -+static/jquery-ui.min.js: jquery-ui-1.11.2 -+ cp jquery-ui-1.11.2/jquery-ui.min.js $@ -+static/jquery-ui.min.css: jquery-ui-1.11.2 -+ cp jquery-ui-1.11.2/jquery-ui.min.css $@ -+static/images: jquery-ui-1.11.2 -+ cp -r jquery-ui-1.11.2/images static/ -diff --git a/dist/source/debugger/README.rst b/dist/source/debugger/README.rst -new file mode 100644 -index 0000000..163d800 ---- /dev/null -+++ b/dist/source/debugger/README.rst -@@ -0,0 +1,385 @@ -+========================================= -+Duktape debug client and JSON debug proxy -+========================================= -+ -+Overview -+======== -+ -+Debugger web UI which connects to the Duktape command line tool or any other -+target supporting the example TCP transport (``examples/debug-trans-socket``) -+on Unix and Windows. -+ -+Also provides a JSON debug proxy with a JSON mapping for the Duktape debug -+protocol. -+ -+For detailed documentation of the debugger internals, see `debugger.rst`__. -+ -+__ https://github.com/svaarala/duktape/blob/master/doc/debugger.rst -+ -+Using the debugger web UI -+========================= -+ -+Some prerequisites: -+ -+* You'll need Node.js v0.10.x or newer. Older Node.js versions don't support -+ the required packages. -+ -+Compile Duktape command line tool with debugger support: -+ -+* Enable ``DUK_USE_DEBUGGER_SUPPORT`` and ``DUK_USE_INTERRUPT_COUNTER`` for -+ ``tools/configure.py``. -+ -+* Enable ``DUK_CMDLINE_DEBUGGER_SUPPORT`` on compiler command line for Duktape -+ command line utility. -+ -+The source distributable contains a Makefile to build a "duk" command with -+debugger support:: -+ -+ $ cd -+ $ make -f Makefile.dukdebug -+ -+The Duktape Git repo "duk" target has debugger support enabled by default:: -+ -+ $ make clean duk -+ -+Start Duktape command line tool so that it waits for a debugger connection:: -+ -+ # For now we need to be in the directory containing the source files -+ # executed so that the 'fileName' properties of functions will match -+ # that on the debug client. -+ -+ # Using source distributable -+ $ cd -+ $ ./duk --debugger mandel.js -+ -+ # Using Duktape Git repo -+ $ cd /tests/ecmascript/ -+ $ ../../duk --debugger test-dev-mandel2-func.js -+ -+Start the web UI:: -+ -+ # Must be in 'debugger' directory. -+ -+ $ cd debugger/ -+ $ make # runs 'node duk_debug.js' -+ -+Once the required packages are installed, the NodeJS debug client will be -+up and running. Open the following in your browser and start debugging: -+ -+* http://localhost:9092/ -+ -+The debug client automatically attaches to the debug target on startup. -+If you start the debug target later, you'll need to click "Attach" in the -+web UI. -+ -+Using the JSON debug proxy -+========================== -+ -+There are two JSON debug proxy implementations: one implemented in DukLuv -+and another in Node.js. -+ -+DukLuv JSON proxy -+----------------- -+ -+DukLuv (https://github.com/creationix/dukluv) is a small and portable event -+loop based on LibUV and Duktape with MIT license (like Duktape). As such it's -+easy to embed in a custom debug client: you just include the DukLuv executable -+and the JSON proxy source file in your debug client. -+ -+Install DukLuv: -+ -+* Ensure ``cmake`` is installed -+ -+* ``git clone https://github.com/creationix/dukluv.git`` -+ -+* ``cd dukluv`` -+ -+* ``git submodule init; git submodule update`` -+ -+* ``make`` -+ -+* Binary should appear in: -+ -+ - ``./build/dukluv`` on Linux -+ -+ - ``.\build\Debug\dukluv.exe`` on Windows -+ -+Run the proxy:: -+ -+ # Using Makefile; autogenerates duk_debug_meta.json -+ # (You may need to edit DUKLUV in Makefile to point to your DukLuv) -+ $ make runproxydukluv -+ -+ # Manually: see "dukluv duk_debug_proxy.js --help" for help -+ $ .../path/to/dukluv duk_debug_proxy.js -+ -+Start Duktape command line (or whatever your target is):: -+ -+ $ cd /tests/ecmascript/ -+ $ ../../duk --debugger test-dev-mandel2-func.js -+ -+Now connect to the proxy using e.g. telnet:: -+ -+ $ telnet localhost 9093 -+ -+The proxy will then connect to the target and you can start issuing commands:: -+ -+ $ telnet localhost 9093 -+ Trying 127.0.0.1... -+ Connected to localhost. -+ Escape character is '^]'. -+ {"notify":"_TargetConnecting","args":["127.0.0.1",9091]} -+ {"notify":"_TargetConnected","args":["1 10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo"]} -+ {"notify":"Status","command":1,"args":[1,"test-dev-mandel2-func.js","global",58,0]} -+ {"request":"BasicInfo"} -+ {"reply":true,"args":[10499,"v1.4.0-140-gc9a6c7c","duk command built from Duktape repo",1]} -+ {"request":"Eval","args":["print('Hello world!'); 123;"]} -+ {"notify":"Print","command":2,"args":["Hello world!\n"]} -+ {"reply":true,"args":[0,{"type":"number","data":"405ec00000000000"}]} -+ [...] -+ -+The proxy log provides dumps both JSON and dvalue binary traffic which is -+quite useful in development:: -+ -+ $ make runproxydukluv -+ Running Dukluv based debug proxy -+ "dukluv" duk_debug_proxy.js --log-level 2 --metadata duk_debug_meta.json -+ 2016-02-17T13:59:42.308Z INF Proxy: Read proxy metadata from duk_debug_meta.json -+ 2016-02-17T13:59:42.325Z INF Proxy: Listening for incoming JSON debug connection on 0.0.0.0:9093, target is 127.0.0.1:9091 -+ 2016-02-17T13:59:47.994Z INF Proxy: JSON proxy client connected -+ 2016-02-17T13:59:47.994Z INF Proxy: Connecting to debug target at 127.0.0.1:9091 -+ 2016-02-17T13:59:47.994Z INF Proxy: PROXY --> CLIENT: {"notify":"_TargetConnecting","args":["127.0.0.1",9091]} -+ 2016-02-17T13:59:47.994Z INF Proxy: Connected to debug target at 127.0.0.1:9091 -+ 2016-02-17T13:59:48.003Z INF Proxy: PROXY --> CLIENT: {"notify":"_TargetConnected","args":["1 10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo"]} -+ 2016-02-17T13:59:48.003Z INF Proxy: Target handshake: {"line":"1 10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo","protocolVersion":1,"text":"10499 v1.4.0-140-gc9a6c7c duk command built from Duktape repo","dukVersion":"1","dukGitDescribe":"10499","targetString":"v1.4.0-140-gc9a6c7c"} -+ 2016-02-17T13:59:48.151Z INF Proxy: PROXY <-- TARGET: |04| -+ 2016-02-17T13:59:48.152Z INF Proxy: PROXY <-- TARGET: |81| -+ 2016-02-17T13:59:48.152Z INF Proxy: PROXY <-- TARGET: |81| -+ 2016-02-17T13:59:48.160Z INF Proxy: PROXY <-- TARGET: |78746573742d6465762d6d616e64656c322d66756e632e6a73| -+ 2016-02-17T13:59:48.161Z INF Proxy: PROXY <-- TARGET: |66676c6f62616c| -+ 2016-02-17T13:59:48.165Z INF Proxy: PROXY <-- TARGET: |ba| -+ 2016-02-17T13:59:48.165Z INF Proxy: PROXY <-- TARGET: |80| -+ 2016-02-17T13:59:48.165Z INF Proxy: PROXY <-- TARGET: |00| -+ 2016-02-17T13:59:48.165Z INF Proxy: PROXY --> CLIENT: {"notify":"Status","command":1,"args":[1,"test-dev-mandel2-func.js","global",58,0]} -+ 2016-02-17T13:59:51.289Z INF Proxy: PROXY <-- CLIENT: {"request":"BasicInfo"} -+ 2016-02-17T13:59:51.289Z INF Proxy: PROXY --> TARGET: |01| -+ 2016-02-17T13:59:51.289Z INF Proxy: PROXY --> TARGET: |90| -+ 2016-02-17T13:59:51.289Z INF Proxy: PROXY --> TARGET: |00| -+ 2016-02-17T13:59:51.291Z INF Proxy: PROXY <-- TARGET: |02| -+ 2016-02-17T13:59:51.291Z INF Proxy: PROXY <-- TARGET: |e903| -+ 2016-02-17T13:59:51.292Z INF Proxy: PROXY <-- TARGET: |7376312e342e302d3134302d6763396136633763| -+ 2016-02-17T13:59:51.293Z INF Proxy: PROXY <-- TARGET: |12002364756b20636f6d6d616e64206275696c742066726f6d2044756b74617065207265706f| -+ 2016-02-17T13:59:51.293Z INF Proxy: PROXY <-- TARGET: |81| -+ 2016-02-17T13:59:51.293Z INF Proxy: PROXY <-- TARGET: |00| -+ 2016-02-17T13:59:51.293Z INF Proxy: PROXY --> CLIENT: {"reply":true,"args":[10499,"v1.4.0-140-gc9a6c7c","duk command built from Duktape repo",1]} -+ 2016-02-17T14:00:06.105Z INF Proxy: PROXY <-- CLIENT: {"request":"Eval","args":["print('Hello world!'); 123;"]} -+ 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |01| -+ 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |9e| -+ 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |7b7072696e74282748656c6c6f20776f726c642127293b203132333b| -+ 2016-02-17T14:00:06.105Z INF Proxy: PROXY --> TARGET: |00| -+ 2016-02-17T14:00:06.167Z INF Proxy: PROXY <-- TARGET: |04| -+ 2016-02-17T14:00:06.167Z INF Proxy: PROXY <-- TARGET: |82| -+ 2016-02-17T14:00:06.167Z INF Proxy: PROXY <-- TARGET: |6d48656c6c6f20776f726c64210a| -+ 2016-02-17T14:00:06.168Z INF Proxy: PROXY <-- TARGET: |00| -+ 2016-02-17T14:00:06.168Z INF Proxy: PROXY --> CLIENT: {"notify":"Print","command":2,"args":["Hello world!\n"]} -+ 2016-02-17T14:00:06.171Z INF Proxy: PROXY <-- TARGET: |02| -+ 2016-02-17T14:00:06.171Z INF Proxy: PROXY <-- TARGET: |80| -+ 2016-02-17T14:00:06.173Z INF Proxy: PROXY <-- TARGET: |1a405ec00000000000| -+ 2016-02-17T14:00:06.173Z INF Proxy: PROXY <-- TARGET: |00| -+ 2016-02-17T14:00:06.174Z INF Proxy: PROXY --> CLIENT: {"reply":true,"args":[0,{"type":"number","data":"405ec00000000000"}]} -+ [...] -+ -+Node.js JSON proxy -+------------------ -+ -+A Node.js-based JSON debug proxy is also provided by ``duk_debug.js``:: -+ -+ # Same prerequisites as for running the debug client -+ $ make runproxynodejs -+ -+Start Duktape command line (or whatever your target is):: -+ -+ $ cd /tests/ecmascript/ -+ $ ../../duk --debugger test-dev-mandel2-func.js -+ -+You can then connect to localhost:9093 and interact with the proxy. -+Here's an example session using telnet and manually typed in commands -+The ``-->`` (send) and ``<--`` (receiver) markers have been added for -+readability and are not part of the stream:: -+ -+ $ telnet localhost 9093 -+ Trying 127.0.0.1... -+ Connected to localhost. -+ Escape character is '^]'. -+ <-- {"notify":"_TargetConnected","args":["1 10199 v1.1.0-275-gbd4d610-dirty duk command built from Duktape repo"]} -+ <-- {"notify":"Status","command":1,"args":[1,"test-dev-mandel2-func.js","global",58,0]} -+ --> {"request":"BasicInfo"} -+ <-- {"reply":true,"args":[10199,"v1.1.0-275-gbd4d610-dirty","duk command built from Duktape repo",1]} -+ --> {"request":"Eval", "args":[ "print(Math.PI)" ]} -+ <-- {"notify":"Print","command":2,"args":["3.141592653589793\n"]} -+ <-- {"reply":true,"args":[0,{"type":"undefined"}]} -+ --> {"request":"Resume"} -+ <-- {"reply":true,"args":[]} -+ <-- {"notify":"Status","command":1,"args":[0,"test-dev-mandel2-func.js","global",58,0]} -+ <-- {"notify":"Status","command":1,"args":[0,"test-dev-mandel2-func.js","global",58,0]} -+ <-- {"notify":"Print","command":2,"args":["................................................................................\n"]} -+ <-- {"notify":"Print","command":2,"args":["................................................................................\n"]} -+ <-- {"notify":"Print","command":2,"args":["................................................................................\n"]} -+ [...] -+ <-- {"notify":"_Disconnecting"} -+ -+A telnet connection allows you to experiment with debug commands by simply -+copy-pasting debug commands to the telnet session. This is useful even if -+you decide to implement the binary protocol directly. -+ -+The debug target used by the proxy can be configured with ``duk_debug.js`` -+command line options. -+ -+Source search path -+================== -+ -+The NodeJS debug client needs to be able to find source code files matching -+code running on the target ("duk" command line). **The filenames used on the -+target and on the debug client must match exactly**, because e.g. breakpoints -+are targeted based on the 'fileName' property of Function objects. -+ -+The search path can be set using the ``--source-dirs`` option given to -+``duk_debug.js``, with the default search paths including only -+``../tests/ecmascript/``. -+ -+The default search path means that if a function on the target has fileName -+``foo/bar.js`` it would be loaded from (relative to the duk_debug.js working -+directory, ``debugger/``):: -+ -+ ../tests/ecmascript/foo/bar.js -+ -+Similarly, if the filesystem contained:: -+ -+ ../tests/ecmascript/baz/quux.js -+ -+the web UI dropdown would show ``baz/quux.js``. If you selected that file -+and added a breakpoint, the breakpoint fileName sent to the debug target -+would be ``baz/quux.js``. -+ -+.. note:: There's much to improve in the search path. For instance, it'd -+ be nice to add a certain path to search but exclude files based -+ on paths and patterns, etc. -+ -+Architecture -+============ -+ -+:: -+ -+ +-------------------+ -+ | Web browser | [debug UI] -+ +-------------------+ -+ | -+ | http (port 9092) -+ | socket.io -+ v -+ +-------------------+ -+ | duk_debug.js | [debug client] -+ +-------------------+ -+ | /\ -+ | || -+ +----------||---- [example tcp transport] (port 9091) -+ | || (application provides concrete transport) -+ | || -+ | ||---- [debug protocol stream] -+ | || (between debug client and Duktape) -+ | || -+ + - - | - - - - -|| - - + -+ : v || : -+  : +-------------||-+ : [target] -+ : | application || | : -+ : +-------------||-+ : -+ : ^ || : -+ : | || : [debug API] -+ : +----------||-------- debug transport callbacks -+ : | || : (read, write, peek, read/write flush) -+ : | || : implemented by application -+ : | \/ : -+ : +----------------+ : -+ : | Duktape | : -+ : +----------------+ : -+ + - - - - - - - - - - - + -+ -+The debug transport is application specific: -+ -+* Duktape command line ("duk") and this debug client use an **example** TCP -+ transport as a concrete example. -+ -+* It is entirely up to the application to come up with the most suitable -+ transport for its environment. Different mechanisms will be needed for -+ Wi-Fi, serial, etc. -+ -+The debug protocol running inside the transport is transport independent: -+ -+* The debug protocol is documented in ``doc/debugger.rst``. -+ -+* This debug client provides further concrete examples and clarifications -+ on how the protocol can be used. -+ -+Using a custom transport -+======================== -+ -+Quite possibly your target device cannot use the example TCP transport and -+you need to implement your own transport. You'll need to implement your -+custom transport both for the target device and for the debug client. -+ -+Target device -+------------- -+ -+Implement the debug transport callbacks needed by ``duk_debugger_attach()``. -+ -+See ``doc/debugger.rst`` for details and ``examples/debug-trans-socket`` -+for example running code for a TCP transport. -+ -+Debug client alternative 1: duk_debug.js + custom TCP proxy -+----------------------------------------------------------- -+ -+If you don't want to change ``duk_debug.js`` you can implement a TCP proxy -+which accepts a TCP connection from ``duk_debug.js`` and then uses your -+custom transport to talk to the target:: -+ -+ +--------------+ TCP +-------+ custom +--------+ -+ | duk_debug.js | ------> | proxy | ---------> | target | -+ +--------------+ +-------+ +--------+ -+ -+This is a straightforward option and a proxy can be used with other debug -+clients too (perhaps custom scripts talking to the target etc). -+ -+You could also use netcat and implement your proxy so that it talks to -+``duk_debug.js`` using stdin/stdout. -+ -+Debug client alternative 2: duk_debug.js + custom NodeJS stream -+--------------------------------------------------------------- -+ -+To make ``duk_debug.js`` use a custom transport you need to: -+ -+* Implement your own transport as NodeJS stream. You can add it directly to -+ ``duk_debug.js`` but it's probably easiest to use a separate module so that -+ the diff to ``duk_debug.js`` stays minimal. -+ -+* Change ``duk_debug.js`` to use the custom transport instead of a TCP -+ stream. Search for "CUSTOMTRANSPORT" in ``duk_debug.js``. -+ -+See: -+ -+* http://nodejs.org/api/stream.html -+ -+* https://github.com/substack/stream-handbook -+ -+Debug client alternative 3: custom debug client -+----------------------------------------------- -+ -+You can also implement your own debug client and debug UI with support for -+your custom transport. -+ -+You'll also need to implement the client part of the Duktape debugger -+protocol. See ``doc/debugger.rst`` for the specification and ``duk_debug.js`` -+for example running code which should illustrate the protocol in more detail. -+ -+The JSON debug proxy allows you to implement a debug client without needing -+to implement the Duktape binary debug protocol. The JSON protocol provides -+a roughly 1:1 mapping to the binary protocol but with an easier syntax. -diff --git a/dist/source/debugger/duk_classnames.yaml b/dist/source/debugger/duk_classnames.yaml -new file mode 100644 -index 0000000..ded0277 ---- /dev/null -+++ b/dist/source/debugger/duk_classnames.yaml -@@ -0,0 +1,32 @@ -+# Must match C header. -+class_names: -+ - none -+ - Object -+ - Array -+ - Function -+ - Arguments -+ - Boolean -+ - Date -+ - Error -+ - JSON -+ - Math -+ - Number -+ - RegExp -+ - String -+ - global -+ - Symbol -+ - ObjEnv -+ - DecEnv -+ - Pointer -+ - Thread -+ - ArrayBuffer -+ - DataView -+ - Int8Array -+ - Uint8Array -+ - Uint8ClampedArray -+ - Int16Array -+ - Uint16Array -+ - Int32Array -+ - Uint32Array -+ - Float32Array -+ - Float64Array -diff --git a/dist/source/debugger/duk_debug.js b/dist/source/debugger/duk_debug.js -new file mode 100644 -index 0000000..e2d0bda ---- /dev/null -+++ b/dist/source/debugger/duk_debug.js -@@ -0,0 +1,2491 @@ -+/* -+ * Minimal debug web console for Duktape command line tool -+ * -+ * See debugger/README.rst. -+ * -+ * The web UI socket.io communication can easily become a bottleneck and -+ * it's important to ensure that the web UI remains responsive. Basic rate -+ * limiting mechanisms (token buckets, suppressing identical messages, etc) -+ * are used here now. Ideally the web UI would pull data on its own terms -+ * which would provide natural rate limiting. -+ * -+ * Promises are used to structure callback chains. -+ * -+ * https://github.com/petkaantonov/bluebird -+ * https://github.com/petkaantonov/bluebird/blob/master/API.md -+ * https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns -+ */ -+ -+var Promise = require('bluebird'); -+var events = require('events'); -+var stream = require('stream'); -+var path = require('path'); -+var fs = require('fs'); -+var net = require('net'); -+var byline = require('byline'); -+var util = require('util'); -+var readline = require('readline'); -+var sprintf = require('sprintf').sprintf; -+var utf8 = require('utf8'); -+var yaml = require('yamljs'); -+var recursiveReadSync = require('recursive-readdir-sync'); -+ -+// Command line options (defaults here, overwritten if necessary) -+var optTargetHost = '127.0.0.1'; -+var optTargetPort = 9091; -+var optHttpPort = 9092; -+var optJsonProxyPort = 9093; -+var optJsonProxy = false; -+var optSourceSearchDirs = [ '../tests/ecmascript' ]; -+var optDumpDebugRead = null; -+var optDumpDebugWrite = null; -+var optDumpDebugPretty = null; -+var optLogMessages = false; -+ -+// Constants -+var UI_MESSAGE_CLIPLEN = 128; -+var LOCALS_CLIPLEN = 64; -+var EVAL_CLIPLEN = 4096; -+var GETVAR_CLIPLEN = 4096; -+var SUPPORTED_DEBUG_PROTOCOL_VERSION = 2; -+ -+// Commands initiated by Duktape -+var CMD_STATUS = 0x01; -+var CMD_UNUSED_2 = 0x02; // Duktape 1.x: print notify -+var CMD_UNUSED_3 = 0x03; // Duktape 1.x: alert notify -+var CMD_UNUSED_4 = 0x04; // Duktape 1.x: log notify -+var CMD_THROW = 0x05; -+var CMD_DETACHING = 0x06; -+ -+// Commands initiated by the debug client (= us) -+var CMD_BASICINFO = 0x10; -+var CMD_TRIGGERSTATUS = 0x11; -+var CMD_PAUSE = 0x12; -+var CMD_RESUME = 0x13; -+var CMD_STEPINTO = 0x14; -+var CMD_STEPOVER = 0x15; -+var CMD_STEPOUT = 0x16; -+var CMD_LISTBREAK = 0x17; -+var CMD_ADDBREAK = 0x18; -+var CMD_DELBREAK = 0x19; -+var CMD_GETVAR = 0x1a; -+var CMD_PUTVAR = 0x1b; -+var CMD_GETCALLSTACK = 0x1c; -+var CMD_GETLOCALS = 0x1d; -+var CMD_EVAL = 0x1e; -+var CMD_DETACH = 0x1f; -+var CMD_DUMPHEAP = 0x20; -+var CMD_GETBYTECODE = 0x21; -+ -+// Errors -+var ERR_UNKNOWN = 0x00; -+var ERR_UNSUPPORTED = 0x01; -+var ERR_TOOMANY = 0x02; -+var ERR_NOTFOUND = 0x03; -+ -+// Marker objects for special protocol values -+var DVAL_EOM = { type: 'eom' }; -+var DVAL_REQ = { type: 'req' }; -+var DVAL_REP = { type: 'rep' }; -+var DVAL_ERR = { type: 'err' }; -+var DVAL_NFY = { type: 'nfy' }; -+ -+// String map for commands (debug dumping). A single map works (instead of -+// separate maps for each direction) because command numbers don't currently -+// overlap. So merge the YAML metadata. -+var debugCommandMeta = yaml.load('duk_debugcommands.yaml'); -+var debugCommandNames = []; // list of command names, merged client/target -+debugCommandMeta.target_commands.forEach(function (k, i) { -+ debugCommandNames[i] = k; -+}); -+debugCommandMeta.client_commands.forEach(function (k, i) { // override -+ debugCommandNames[i] = k; -+}); -+var debugCommandNumbers = {}; // map from (merged) command name to number -+debugCommandNames.forEach(function (k, i) { -+ debugCommandNumbers[k] = i; -+}); -+ -+// Duktape heaphdr type constants, must match C headers -+var DUK_HTYPE_STRING = 0; -+var DUK_HTYPE_OBJECT = 1; -+var DUK_HTYPE_BUFFER = 2; -+ -+// Duktape internal class numbers, must match C headers -+var dukClassNameMeta = yaml.load('duk_classnames.yaml'); -+var dukClassNames = dukClassNameMeta.class_names; -+ -+// Bytecode opcode/extraop metadata -+var dukOpcodes = yaml.load('duk_opcodes.yaml'); -+if (dukOpcodes.opcodes.length != 256) { -+ throw new Error('opcode metadata length incorrect'); -+} -+ -+/* -+ * Miscellaneous helpers -+ */ -+ -+var nybbles = '0123456789abcdef'; -+ -+/* Convert a buffer into a string using Unicode codepoints U+0000...U+00FF. -+ * This is the NodeJS 'binary' encoding, but since it's being deprecated, -+ * reimplement it here. We need to avoid parsing strings as e.g. UTF-8: -+ * although Duktape strings are usually UTF-8/CESU-8 that's not always the -+ * case, e.g. for internal strings. Buffer values are also represented as -+ * strings in the debug protocol, so we must deal accurately with arbitrary -+ * byte arrays. -+ */ -+function bufferToDebugString(buf) { -+ var cp = []; -+ var i, n; -+ -+/* -+ // This fails with "RangeError: Maximum call stack size exceeded" for some -+ // reason, so use a much slower variant. -+ -+ for (i = 0, n = buf.length; i < n; i++) { -+ cp[i] = buf[i]; -+ } -+ -+ return String.fromCharCode.apply(String, cp); -+*/ -+ -+ for (i = 0, n = buf.length; i < n; i++) { -+ cp[i] = String.fromCharCode(buf[i]); -+ } -+ -+ return cp.join(''); -+} -+ -+/* Write a string into a buffer interpreting codepoints U+0000...U+00FF -+ * as bytes. Drop higher bits. -+ */ -+function writeDebugStringToBuffer(str, buf, off) { -+ var i, n; -+ -+ for (i = 0, n = str.length; i < n; i++) { -+ buf[off + i] = str.charCodeAt(i) & 0xff; // truncate higher bits -+ } -+} -+ -+/* Encode an ordinary Unicode string into a dvalue compatible format, i.e. -+ * into a byte array represented as codepoints U+0000...U+00FF. Concretely, -+ * encode with UTF-8 and then represent the bytes with U+0000...U+00FF. -+ */ -+function stringToDebugString(str) { -+ return utf8.encode(str); -+} -+ -+/* Pretty print a dvalue. Useful for dumping etc. */ -+function prettyDebugValue(x) { -+ if (typeof x === 'object' && x !== null) { -+ if (x.type === 'eom') { -+ return 'EOM'; -+ } else if (x.type === 'req') { -+ return 'REQ'; -+ } else if (x.type === 'rep') { -+ return 'REP'; -+ } else if (x.type === 'err') { -+ return 'ERR'; -+ } else if (x.type === 'nfy') { -+ return 'NFY'; -+ } -+ } -+ return JSON.stringify(x); -+} -+ -+/* Pretty print a number for UI usage. Types and values should be easy to -+ * read and typing should be obvious. For numbers, support Infinity, NaN, -+ * and signed zeroes properly. -+ */ -+function prettyUiNumber(x) { -+ if (x === 1 / 0) { return 'Infinity'; } -+ if (x === -1 / 0) { return '-Infinity'; } -+ if (Number.isNaN(x)) { return 'NaN'; } -+ if (x === 0 && 1 / x > 0) { return '0'; } -+ if (x === 0 && 1 / x < 0) { return '-0'; } -+ return x.toString(); -+} -+ -+/* Pretty print a dvalue string (bytes represented as U+0000...U+00FF) -+ * for UI usage. Try UTF-8 decoding to get a nice Unicode string (JSON -+ * encoded) but if that fails, ensure that bytes are encoded transparently. -+ * The result is a quoted string with a special quote marker for a "raw" -+ * string when UTF-8 decoding fails. Very long strings are optionally -+ * clipped. -+ */ -+function prettyUiString(x, cliplen) { -+ var ret; -+ -+ if (typeof x !== 'string') { -+ throw new Error('invalid input to prettyUiString: ' + typeof x); -+ } -+ try { -+ // Here utf8.decode() is better than decoding using NodeJS buffer -+ // operations because we want strict UTF-8 interpretation. -+ ret = JSON.stringify(utf8.decode(x)); -+ } catch (e) { -+ // When we fall back to representing bytes, indicate that the string -+ // is "raw" with a 'r"' prefix (a somewhat arbitrary convention). -+ // U+0022 = ", U+0027 = ' -+ ret = 'r"' + x.replace(/[\u0022\u0027\u0000-\u001f\u0080-\uffff]/g, function (match) { -+ var cp = match.charCodeAt(0); -+ return '\\x' + nybbles[(cp >> 4) & 0x0f] + nybbles[cp & 0x0f]; -+ }) + '"'; -+ } -+ -+ if (cliplen && ret.length > cliplen) { -+ ret = ret.substring(0, cliplen) + '...'; // trailing '"' intentionally missing -+ } -+ return ret; -+} -+ -+/* Pretty print a dvalue string (bytes represented as U+0000...U+00FF) -+ * for UI usage without quotes. -+ */ -+function prettyUiStringUnquoted(x, cliplen) { -+ var ret; -+ -+ if (typeof x !== 'string') { -+ throw new Error('invalid input to prettyUiStringUnquoted: ' + typeof x); -+ } -+ -+ try { -+ // Here utf8.decode() is better than decoding using NodeJS buffer -+ // operations because we want strict UTF-8 interpretation. -+ -+ // XXX: unprintable characters etc? In some UI cases we'd want to -+ // e.g. escape newlines and in others not. -+ ret = utf8.decode(x); -+ } catch (e) { -+ // For the unquoted version we don't need to escape single or double -+ // quotes. -+ ret = x.replace(/[\u0000-\u001f\u0080-\uffff]/g, function (match) { -+ var cp = match.charCodeAt(0); -+ return '\\x' + nybbles[(cp >> 4) & 0x0f] + nybbles[cp & 0x0f]; -+ }); -+ } -+ -+ if (cliplen && ret.length > cliplen) { -+ ret = ret.substring(0, cliplen) + '...'; -+ } -+ return ret; -+} -+ -+/* Pretty print a dvalue for UI usage. Everything comes out as a ready-to-use -+ * string. -+ * -+ * XXX: Currently the debug client formats all values for UI use. A better -+ * solution would be to pass values in typed form and let the UI format them, -+ * so that styling etc. could take typing into account. -+ */ -+function prettyUiDebugValue(x, cliplen) { -+ if (typeof x === 'object' && x !== null) { -+ // Note: typeof null === 'object', so null special case explicitly -+ if (x.type === 'eom') { -+ return 'EOM'; -+ } else if (x.type === 'req') { -+ return 'REQ'; -+ } else if (x.type === 'rep') { -+ return 'REP'; -+ } else if (x.type === 'err') { -+ return 'ERR'; -+ } else if (x.type === 'nfy') { -+ return 'NFY'; -+ } else if (x.type === 'unused') { -+ return 'unused'; -+ } else if (x.type === 'undefined') { -+ return 'undefined'; -+ } else if (x.type === 'buffer') { -+ return '|' + x.data + '|'; -+ } else if (x.type === 'object') { -+ return '[object ' + (dukClassNames[x.class] || ('class ' + x.class)) + ' ' + x.pointer + ']'; -+ } else if (x.type === 'pointer') { -+ return ''; -+ } else if (x.type === 'lightfunc') { -+ return ''; -+ } else if (x.type === 'number') { -+ // duk_tval number, any IEEE double -+ var tmp = new Buffer(x.data, 'hex'); // decode into hex -+ var val = tmp.readDoubleBE(0); // big endian ieee double -+ return prettyUiNumber(val); -+ } -+ } else if (x === null) { -+ return 'null'; -+ } else if (typeof x === 'boolean') { -+ return x ? 'true' : 'false'; -+ } else if (typeof x === 'string') { -+ return prettyUiString(x, cliplen); -+ } else if (typeof x === 'number') { -+ // Debug protocol integer -+ return prettyUiNumber(x); -+ } -+ -+ // We shouldn't come here, but if we do, JSON is a reasonable default. -+ return JSON.stringify(x); -+} -+ -+/* Pretty print a debugger message given as an array of parsed dvalues. -+ * Result should be a pure ASCII one-liner. -+ */ -+function prettyDebugMessage(msg) { -+ return msg.map(prettyDebugValue).join(' '); -+} -+ -+/* Pretty print a debugger command. */ -+function prettyDebugCommand(cmd) { -+ return debugCommandNames[cmd] || String(cmd); -+} -+ -+/* Decode and normalize source file contents: UTF-8, tabs to 8, -+ * CR LF to LF. -+ */ -+function decodeAndNormalizeSource(data) { -+ var tmp; -+ var lines, line, repl; -+ var i, n; -+ var j, m; -+ -+ try { -+ tmp = data.toString('utf8'); -+ } catch (e) { -+ console.log('Failed to UTF-8 decode source file, ignoring: ' + e); -+ tmp = String(data); -+ } -+ -+ lines = tmp.split(/\r?\n/); -+ for (i = 0, n = lines.length; i < n; i++) { -+ line = lines[i]; -+ if (/\t/.test(line)) { -+ repl = ''; -+ for (j = 0, m = line.length; j < m; j++) { -+ if (line.charAt(j) === '\t') { -+ repl += ' '; -+ while ((repl.length % 8) != 0) { -+ repl += ' '; -+ } -+ } else { -+ repl += line.charAt(j); -+ } -+ } -+ lines[i] = repl; -+ } -+ } -+ -+ // XXX: normalize last newline (i.e. force a newline if contents don't -+ // end with a newline)? -+ -+ return lines.join('\n'); -+} -+ -+/* Token bucket rate limiter for a given callback. Calling code calls -+ * trigger() to request 'cb' to be called, and the rate limiter ensures -+ * that 'cb' is not called too often. -+ */ -+function RateLimited(tokens, rate, cb) { -+ var _this = this; -+ this.maxTokens = tokens; -+ this.tokens = this.maxTokens; -+ this.rate = rate; -+ this.cb = cb; -+ this.delayedCb = false; -+ -+ // Right now the implementation is setInterval-based, but could also be -+ // made timerless. There are so few rate limited resources that this -+ // doesn't matter in practice. -+ -+ this.tokenAdder = setInterval(function () { -+ if (_this.tokens < _this.maxTokens) { -+ _this.tokens++; -+ } -+ if (_this.delayedCb) { -+ _this.delayedCb = false; -+ _this.tokens--; -+ _this.cb(); -+ } -+ }, this.rate); -+} -+RateLimited.prototype.trigger = function () { -+ if (this.tokens > 0) { -+ this.tokens--; -+ this.cb(); -+ } else { -+ this.delayedCb = true; -+ } -+}; -+ -+/* -+ * Source file manager -+ * -+ * Scan the list of search directories for ECMAScript source files and -+ * build an index of them. Provides a mechanism to find a source file -+ * based on a raw 'fileName' property provided by the debug target, and -+ * to provide a file list for the web UI. -+ * -+ * NOTE: it's tempting to do loose matching for filenames, but this does -+ * not work in practice. Filenames must match 1:1 with the debug target -+ * so that e.g. breakpoints assigned based on filenames found from the -+ * search paths will match 1:1 on the debug target. If this is not the -+ * case, breakpoints won't work as expected. -+ */ -+ -+function SourceFileManager(directories) { -+ this.directories = directories; -+ this.extensions = { '.js': true, '.jsm': true }; -+ this.fileMap = {}; // filename as seen by debug target -> file path -+ this.files = []; // filenames as seen by debug target -+} -+ -+SourceFileManager.prototype.scan = function () { -+ var _this = this; -+ var fileMap = {}; // relative path -> file path -+ var files; -+ -+ this.directories.forEach(function (dir) { -+ console.log('Scanning source files: ' + dir); -+ try { -+ recursiveReadSync(dir).forEach(function (fn) { -+ // Example: dir ../../tests -+ // normFn ../../tests/foo/bar.js -+ // relFn foo/bar.js -+ var normDir = path.normalize(dir); -+ var normFn = path.normalize(fn); -+ var relFn = path.relative(normDir, normFn); -+ -+ if (fs.existsSync(normFn) && fs.lstatSync(normFn).isFile() && -+ _this.extensions[path.extname(normFn)]) { -+ // We want the fileMap to contain the filename relative to -+ // the search dir root. First directory containing a -+ // certail relFn wins. -+ if (relFn in fileMap) { -+ console.log('Found', relFn, 'multiple times, first match wins'); -+ } else { -+ fileMap[relFn] = normFn; -+ } -+ } -+ }); -+ } catch (e) { -+ console.log('Failed to scan ' + dir + ': ' + e); -+ } -+ }); -+ -+ files = Object.keys(fileMap); -+ files.sort(); -+ this.files = files; -+ -+ this.fileMap = fileMap; -+ -+ console.log('Found ' + files.length + ' source files in ' + this.directories.length + ' search directories'); -+}; -+ -+SourceFileManager.prototype.getFiles = function () { -+ return this.files; -+}; -+ -+SourceFileManager.prototype.search = function (fileName) { -+ var _this = this; -+ -+ // Loose matching is tempting but counterproductive: filenames must -+ // match 1:1 between the debug client and the debug target for e.g. -+ // breakpoints to work as expected. Note that a breakpoint may be -+ // assigned by selecting a file from a dropdown populated by scanning -+ // the filesystem for available sources and there's no way of knowing -+ // if the debug target uses the exact same name. -+ // -+ // We intentionally allow any files from the search paths, not just -+ // those scanned to this.fileMap. -+ -+ function tryLookup() { -+ var i, fn, data; -+ -+ for (i = 0; i < _this.directories.length; i++) { -+ fn = path.join(_this.directories[i], fileName); -+ if (fs.existsSync(fn) && fs.lstatSync(fn).isFile()) { -+ data = fs.readFileSync(fn); // Raw bytes -+ return decodeAndNormalizeSource(data); // Unicode string -+ } -+ } -+ return null; -+ } -+ -+ return tryLookup(fileName); -+}; -+ -+/* -+ * Debug protocol parser -+ * -+ * The debug protocol parser is an EventEmitter which parses debug messages -+ * from an input stream and emits 'debug-message' events for completed -+ * messages ending in an EOM. The parser also provides debug dumping, stream -+ * logging functionality, and statistics gathering functionality. -+ * -+ * This parser is used to parse both incoming and outgoing messages. For -+ * outgoing messages the only function is to validate and debug dump the -+ * messages we're about to send. The downside of dumping at this low level -+ * is that we can't match request and reply/error messages here. -+ * -+ * http://www.sitepoint.com/nodejs-events-and-eventemitter/ -+ */ -+ -+function DebugProtocolParser(inputStream, -+ protocolVersion, -+ rawDumpFileName, -+ textDumpFileName, -+ textDumpFilePrefix, -+ hexDumpConsolePrefix, -+ textDumpConsolePrefix) { -+ var _this = this; -+ this.inputStream = inputStream; -+ this.closed = false; // stream is closed/broken, don't parse anymore -+ this.bytes = 0; -+ this.dvalues = 0; -+ this.messages = 0; -+ this.requests = 0; -+ this.prevBytes = 0; -+ this.bytesPerSec = 0; -+ this.statsTimer = null; -+ this.readableNumberValue = true; -+ -+ events.EventEmitter.call(this); -+ -+ var buf = new Buffer(0); // accumulate data -+ var msg = []; // accumulated message until EOM -+ var versionIdentification; -+ -+ var statsInterval = 2000; -+ var statsIntervalSec = statsInterval / 1000; -+ this.statsTimer = setInterval(function () { -+ _this.bytesPerSec = (_this.bytes - _this.prevBytes) / statsIntervalSec; -+ _this.prevBytes = _this.bytes; -+ _this.emit('stats-update'); -+ }, statsInterval); -+ -+ function consume(n) { -+ var tmp = new Buffer(buf.length - n); -+ buf.copy(tmp, 0, n); -+ buf = tmp; -+ } -+ -+ inputStream.on('data', function (data) { -+ var i, n, x, v, gotValue, len, t, tmpbuf, verstr; -+ var prettyMsg; -+ -+ if (_this.closed || !_this.inputStream) { -+ console.log('Ignoring incoming data from closed input stream, len ' + data.length); -+ return; -+ } -+ -+ _this.bytes += data.length; -+ if (rawDumpFileName) { -+ fs.appendFileSync(rawDumpFileName, data); -+ } -+ if (hexDumpConsolePrefix) { -+ console.log(hexDumpConsolePrefix + data.toString('hex')); -+ } -+ -+ buf = Buffer.concat([ buf, data ]); -+ -+ // Protocol version handling. When dumping an output stream, the -+ // caller gives a non-null protocolVersion so we don't read one here. -+ if (protocolVersion == null) { -+ if (buf.length > 1024) { -+ _this.emit('transport-error', 'Parse error (version identification too long), dropping connection'); -+ _this.close(); -+ return; -+ } -+ -+ for (i = 0, n = buf.length; i < n; i++) { -+ if (buf[i] == 0x0a) { -+ tmpbuf = new Buffer(i); -+ buf.copy(tmpbuf, 0, 0, i); -+ consume(i + 1); -+ verstr = tmpbuf.toString('utf-8'); -+ t = verstr.split(' '); -+ protocolVersion = Number(t[0]); -+ versionIdentification = verstr; -+ -+ _this.emit('protocol-version', { -+ protocolVersion: protocolVersion, -+ versionIdentification: versionIdentification -+ }); -+ break; -+ } -+ } -+ -+ if (protocolVersion == null) { -+ // Still waiting for version identification to complete. -+ return; -+ } -+ } -+ -+ // Parse complete dvalues (quite inefficient now) by trial parsing. -+ // Consume a value only when it's fully present in 'buf'. -+ // See doc/debugger.rst for format description. -+ -+ while (buf.length > 0) { -+ x = buf[0]; -+ v = undefined; -+ gotValue = false; // used to flag special values like undefined -+ -+ if (x >= 0xc0) { -+ // 0xc0...0xff: integers 0-16383 -+ if (buf.length >= 2) { -+ v = ((x - 0xc0) << 8) + buf[1]; -+ consume(2); -+ } -+ } else if (x >= 0x80) { -+ // 0x80...0xbf: integers 0-63 -+ v = x - 0x80; -+ consume(1); -+ } else if (x >= 0x60) { -+ // 0x60...0x7f: strings with length 0-31 -+ len = x - 0x60; -+ if (buf.length >= 1 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 1, 1 + len); -+ v = bufferToDebugString(v); -+ consume(1 + len); -+ } -+ } else { -+ switch (x) { -+ case 0x00: v = DVAL_EOM; consume(1); break; -+ case 0x01: v = DVAL_REQ; consume(1); break; -+ case 0x02: v = DVAL_REP; consume(1); break; -+ case 0x03: v = DVAL_ERR; consume(1); break; -+ case 0x04: v = DVAL_NFY; consume(1); break; -+ case 0x10: // 4-byte signed integer -+ if (buf.length >= 5) { -+ v = buf.readInt32BE(1); -+ consume(5); -+ } -+ break; -+ case 0x11: // 4-byte string -+ if (buf.length >= 5) { -+ len = buf.readUInt32BE(1); -+ if (buf.length >= 5 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 5, 5 + len); -+ v = bufferToDebugString(v); -+ consume(5 + len); -+ } -+ } -+ break; -+ case 0x12: // 2-byte string -+ if (buf.length >= 3) { -+ len = buf.readUInt16BE(1); -+ if (buf.length >= 3 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 3, 3 + len); -+ v = bufferToDebugString(v); -+ consume(3 + len); -+ } -+ } -+ break; -+ case 0x13: // 4-byte buffer -+ if (buf.length >= 5) { -+ len = buf.readUInt32BE(1); -+ if (buf.length >= 5 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 5, 5 + len); -+ v = { type: 'buffer', data: v.toString('hex') }; -+ consume(5 + len); -+ // Value could be a Node.js buffer directly, but -+ // we prefer all dvalues to be JSON compatible -+ } -+ } -+ break; -+ case 0x14: // 2-byte buffer -+ if (buf.length >= 3) { -+ len = buf.readUInt16BE(1); -+ if (buf.length >= 3 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 3, 3 + len); -+ v = { type: 'buffer', data: v.toString('hex') }; -+ consume(3 + len); -+ // Value could be a Node.js buffer directly, but -+ // we prefer all dvalues to be JSON compatible -+ } -+ } -+ break; -+ case 0x15: // unused/none -+ v = { type: 'unused' }; -+ consume(1); -+ break; -+ case 0x16: // undefined -+ v = { type: 'undefined' }; -+ gotValue = true; // indicate 'v' is actually set -+ consume(1); -+ break; -+ case 0x17: // null -+ v = null; -+ gotValue = true; // indicate 'v' is actually set -+ consume(1); -+ break; -+ case 0x18: // true -+ v = true; -+ consume(1); -+ break; -+ case 0x19: // false -+ v = false; -+ consume(1); -+ break; -+ case 0x1a: // number (IEEE double), big endian -+ if (buf.length >= 9) { -+ v = new Buffer(8); -+ buf.copy(v, 0, 1, 9); -+ v = { type: 'number', data: v.toString('hex') }; -+ -+ if (_this.readableNumberValue) { -+ // The value key should not be used programmatically, -+ // it is just there to make the dumps more readable. -+ v.value = buf.readDoubleBE(1); -+ } -+ consume(9); -+ } -+ break; -+ case 0x1b: // object -+ if (buf.length >= 3) { -+ len = buf[2]; -+ if (buf.length >= 3 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 3, 3 + len); -+ v = { type: 'object', 'class': buf[1], pointer: v.toString('hex') }; -+ consume(3 + len); -+ } -+ } -+ break; -+ case 0x1c: // pointer -+ if (buf.length >= 2) { -+ len = buf[1]; -+ if (buf.length >= 2 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 2, 2 + len); -+ v = { type: 'pointer', pointer: v.toString('hex') }; -+ consume(2 + len); -+ } -+ } -+ break; -+ case 0x1d: // lightfunc -+ if (buf.length >= 4) { -+ len = buf[3]; -+ if (buf.length >= 4 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 4, 4 + len); -+ v = { type: 'lightfunc', flags: buf.readUInt16BE(1), pointer: v.toString('hex') }; -+ consume(4 + len); -+ } -+ } -+ break; -+ case 0x1e: // heapptr -+ if (buf.length >= 2) { -+ len = buf[1]; -+ if (buf.length >= 2 + len) { -+ v = new Buffer(len); -+ buf.copy(v, 0, 2, 2 + len); -+ v = { type: 'heapptr', pointer: v.toString('hex') }; -+ consume(2 + len); -+ } -+ } -+ break; -+ default: -+ _this.emit('transport-error', 'Parse error, dropping connection'); -+ _this.close(); -+ } -+ } -+ -+ if (typeof v === 'undefined' && !gotValue) { -+ break; -+ } -+ msg.push(v); -+ _this.dvalues++; -+ -+ // Could emit a 'debug-value' event here, but that's not necessary -+ // because the receiver will just collect statistics which can also -+ // be done using the finished message. -+ -+ if (v === DVAL_EOM) { -+ _this.messages++; -+ -+ if (textDumpFileName || textDumpConsolePrefix) { -+ prettyMsg = prettyDebugMessage(msg); -+ if (textDumpFileName) { -+ fs.appendFileSync(textDumpFileName, (textDumpFilePrefix || '') + prettyMsg + '\n'); -+ } -+ if (textDumpConsolePrefix) { -+ console.log(textDumpConsolePrefix + prettyMsg); -+ } -+ } -+ -+ _this.emit('debug-message', msg); -+ msg = []; // new object, old may be in circulation for a while -+ } -+ } -+ }); -+ -+ // Not all streams will emit this. -+ inputStream.on('error', function (err) { -+ _this.emit('transport-error', err); -+ _this.close(); -+ }); -+ -+ // Not all streams will emit this. -+ inputStream.on('close', function () { -+ _this.close(); -+ }); -+} -+DebugProtocolParser.prototype = Object.create(events.EventEmitter.prototype); -+ -+DebugProtocolParser.prototype.close = function () { -+ // Although the underlying transport may not have a close() or destroy() -+ // method or even a 'close' event, this method is always available and -+ // will generate a 'transport-close'. -+ // -+ // The caller is responsible for closing the underlying stream if that -+ // is necessary. -+ -+ if (this.closed) { return; } -+ -+ this.closed = true; -+ if (this.statsTimer) { -+ clearInterval(this.statsTimer); -+ this.statsTimer = null; -+ } -+ this.emit('transport-close'); -+}; -+ -+/* -+ * Debugger output formatting -+ */ -+ -+function formatDebugValue(v) { -+ var buf, dec, len; -+ -+ // See doc/debugger.rst for format description. -+ -+ if (typeof v === 'object' && v !== null) { -+ // Note: typeof null === 'object', so null special case explicitly -+ if (v.type === 'eom') { -+ return new Buffer([ 0x00 ]); -+ } else if (v.type === 'req') { -+ return new Buffer([ 0x01 ]); -+ } else if (v.type === 'rep') { -+ return new Buffer([ 0x02 ]); -+ } else if (v.type === 'err') { -+ return new Buffer([ 0x03 ]); -+ } else if (v.type === 'nfy') { -+ return new Buffer([ 0x04 ]); -+ } else if (v.type === 'unused') { -+ return new Buffer([ 0x15 ]); -+ } else if (v.type === 'undefined') { -+ return new Buffer([ 0x16 ]); -+ } else if (v.type === 'number') { -+ dec = new Buffer(v.data, 'hex'); -+ len = dec.length; -+ if (len !== 8) { -+ throw new TypeError('value cannot be converted to dvalue: ' + JSON.stringify(v)); -+ } -+ buf = new Buffer(1 + len); -+ buf[0] = 0x1a; -+ dec.copy(buf, 1); -+ return buf; -+ } else if (v.type === 'buffer') { -+ dec = new Buffer(v.data, 'hex'); -+ len = dec.length; -+ if (len <= 0xffff) { -+ buf = new Buffer(3 + len); -+ buf[0] = 0x14; -+ buf[1] = (len >> 8) & 0xff; -+ buf[2] = (len >> 0) & 0xff; -+ dec.copy(buf, 3); -+ return buf; -+ } else { -+ buf = new Buffer(5 + len); -+ buf[0] = 0x13; -+ buf[1] = (len >> 24) & 0xff; -+ buf[2] = (len >> 16) & 0xff; -+ buf[3] = (len >> 8) & 0xff; -+ buf[4] = (len >> 0) & 0xff; -+ dec.copy(buf, 5); -+ return buf; -+ } -+ } else if (v.type === 'object') { -+ dec = new Buffer(v.pointer, 'hex'); -+ len = dec.length; -+ buf = new Buffer(3 + len); -+ buf[0] = 0x1b; -+ buf[1] = v.class; -+ buf[2] = len; -+ dec.copy(buf, 3); -+ return buf; -+ } else if (v.type === 'pointer') { -+ dec = new Buffer(v.pointer, 'hex'); -+ len = dec.length; -+ buf = new Buffer(2 + len); -+ buf[0] = 0x1c; -+ buf[1] = len; -+ dec.copy(buf, 2); -+ return buf; -+ } else if (v.type === 'lightfunc') { -+ dec = new Buffer(v.pointer, 'hex'); -+ len = dec.length; -+ buf = new Buffer(4 + len); -+ buf[0] = 0x1d; -+ buf[1] = (v.flags >> 8) & 0xff; -+ buf[2] = v.flags & 0xff; -+ buf[3] = len; -+ dec.copy(buf, 4); -+ return buf; -+ } else if (v.type === 'heapptr') { -+ dec = new Buffer(v.pointer, 'hex'); -+ len = dec.length; -+ buf = new Buffer(2 + len); -+ buf[0] = 0x1e; -+ buf[1] = len; -+ dec.copy(buf, 2); -+ return buf; -+ } -+ } else if (v === null) { -+ return new Buffer([ 0x17 ]); -+ } else if (typeof v === 'boolean') { -+ return new Buffer([ v ? 0x18 : 0x19 ]); -+ } else if (typeof v === 'number') { -+ if (Math.floor(v) === v && /* whole */ -+ (v !== 0 || 1 / v > 0) && /* not negative zero */ -+ v >= -0x80000000 && v <= 0x7fffffff) { -+ // Represented signed 32-bit integers as plain integers. -+ // Debugger code expects this for all fields that are not -+ // duk_tval representations (e.g. command numbers and such). -+ if (v >= 0x00 && v <= 0x3f) { -+ return new Buffer([ 0x80 + v ]); -+ } else if (v >= 0x0000 && v <= 0x3fff) { -+ return new Buffer([ 0xc0 + (v >> 8), v & 0xff ]); -+ } else if (v >= -0x80000000 && v <= 0x7fffffff) { -+ return new Buffer([ 0x10, -+ (v >> 24) & 0xff, -+ (v >> 16) & 0xff, -+ (v >> 8) & 0xff, -+ (v >> 0) & 0xff ]); -+ } else { -+ throw new Error('internal error when encoding integer to dvalue: ' + v); -+ } -+ } else { -+ // Represent non-integers as IEEE double dvalues -+ buf = new Buffer(1 + 8); -+ buf[0] = 0x1a; -+ buf.writeDoubleBE(v, 1); -+ return buf; -+ } -+ } else if (typeof v === 'string') { -+ if (v.length < 0 || v.length > 0xffffffff) { -+ // Not possible in practice. -+ throw new TypeError('cannot convert to dvalue, invalid string length: ' + v.length); -+ } -+ if (v.length <= 0x1f) { -+ buf = new Buffer(1 + v.length); -+ buf[0] = 0x60 + v.length; -+ writeDebugStringToBuffer(v, buf, 1); -+ return buf; -+ } else if (v.length <= 0xffff) { -+ buf = new Buffer(3 + v.length); -+ buf[0] = 0x12; -+ buf[1] = (v.length >> 8) & 0xff; -+ buf[2] = (v.length >> 0) & 0xff; -+ writeDebugStringToBuffer(v, buf, 3); -+ return buf; -+ } else { -+ buf = new Buffer(5 + v.length); -+ buf[0] = 0x11; -+ buf[1] = (v.length >> 24) & 0xff; -+ buf[2] = (v.length >> 16) & 0xff; -+ buf[3] = (v.length >> 8) & 0xff; -+ buf[4] = (v.length >> 0) & 0xff; -+ writeDebugStringToBuffer(v, buf, 5); -+ return buf; -+ } -+ } -+ -+ // Shouldn't come here. -+ throw new TypeError('value cannot be converted to dvalue: ' + JSON.stringify(v)); -+} -+ -+/* -+ * Debugger implementation -+ * -+ * A debugger instance communicates with the debug target and maintains -+ * persistent debug state so that the current state can be resent to the -+ * socket.io client (web UI) if it reconnects. Whenever the debugger state -+ * is changed an event is generated. The socket.io handler will listen to -+ * state change events and push the necessary updates to the web UI, often -+ * in a rate limited fashion or using a client pull to ensure the web UI -+ * is not overloaded. -+ * -+ * The debugger instance assumes that if the debug protocol connection is -+ * re-established, it is always to the same target. There is no separate -+ * abstraction for a debugger session. -+ */ -+ -+function Debugger() { -+ events.EventEmitter.call(this); -+ -+ this.web = null; // web UI singleton -+ this.targetStream = null; // transport connection to target -+ this.outputPassThroughStream = null; // dummy passthrough for message dumping -+ this.inputParser = null; // parser for incoming debug messages -+ this.outputParser = null; // parser for outgoing debug messages (stats, dumping) -+ this.protocolVersion = null; -+ this.dukVersion = null; -+ this.dukGitDescribe = null; -+ this.targetInfo = null; -+ this.attached = false; -+ this.handshook = false; -+ this.reqQueue = null; -+ this.stats = { // stats for current debug connection -+ rxBytes: 0, rxDvalues: 0, rxMessages: 0, rxBytesPerSec: 0, -+ txBytes: 0, txDvalues: 0, txMessages: 0, txBytesPerSec: 0 -+ }; -+ this.execStatus = { -+ attached: false, -+ state: 'detached', -+ fileName: '', -+ funcName: '', -+ line: 0, -+ pc: 0 -+ }; -+ this.breakpoints = []; -+ this.callstack = []; -+ this.locals = []; -+ this.messageLines = []; -+ this.messageScrollBack = 100; -+} -+Debugger.prototype = events.EventEmitter.prototype; -+ -+Debugger.prototype.decodeBytecodeFromBuffer = function (buf, consts, funcs) { -+ var i, j, n, m, ins, pc; -+ var res = []; -+ var op, str, args, comments; -+ -+ // XXX: add constants inline to preformatted output (e.g. for strings, -+ // add a short escaped snippet as a comment on the line after the -+ // compact argument list). -+ -+ for (i = 0, n = buf.length; i < n; i += 4) { -+ pc = i / 4; -+ -+ // shift forces unsigned -+ if (this.endianness === 'little') { -+ ins = buf.readInt32LE(i) >>> 0; -+ } else { -+ ins = buf.readInt32BE(i) >>> 0; -+ } -+ -+ op = dukOpcodes.opcodes[ins & 0xff]; -+ -+ args = []; -+ comments = []; -+ if (op.args) { -+ for (j = 0, m = op.args.length; j < m; j++) { -+ var A = (ins >>> 8) & 0xff; -+ var B = (ins >>> 16) & 0xff; -+ var C = (ins >>> 24) & 0xff; -+ var BC = (ins >>> 16) & 0xffff; -+ var ABC = (ins >>> 8) & 0xffffff; -+ var Bconst = op & 0x01; -+ var Cconst = op & 0x02; -+ -+ switch (op.args[j]) { -+ case 'A_R': args.push('r' + A); break; -+ case 'A_RI': args.push('r' + A + '(indirect)'); break; -+ case 'A_C': args.push('c' + A); break; -+ case 'A_H': args.push('0x' + A.toString(16)); break; -+ case 'A_I': args.push(A.toString(10)); break; -+ case 'A_B': args.push(A ? 'true' : 'false'); break; -+ case 'B_RC': args.push((Bconst ? 'c' : 'r') + B); break; -+ case 'B_R': args.push('r' + B); break; -+ case 'B_RI': args.push('r' + B + '(indirect)'); break; -+ case 'B_C': args.push('c' + B); break; -+ case 'B_H': args.push('0x' + B.toString(16)); break; -+ case 'B_I': args.push(B.toString(10)); break; -+ case 'C_RC': args.push((Cconst ? 'c' : 'r') + C); break; -+ case 'C_R': args.push('r' + C); break; -+ case 'C_RI': args.push('r' + C + '(indirect)'); break; -+ case 'C_C': args.push('c' + C); break; -+ case 'C_H': args.push('0x' + C.toString(16)); break; -+ case 'C_I': args.push(C.toString(10)); break; -+ case 'BC_R': args.push('r' + BC); break; -+ case 'BC_C': args.push('c' + BC); break; -+ case 'BC_H': args.push('0x' + BC.toString(16)); break; -+ case 'BC_I': args.push(BC.toString(10)); break; -+ case 'ABC_H': args.push(ABC.toString(16)); break; -+ case 'ABC_I': args.push(ABC.toString(10)); break; -+ case 'BC_LDINT': args.push(BC - (1 << 15)); break; -+ case 'BC_LDINTX': args.push(BC - 0); break; // no bias in LDINTX -+ case 'ABC_JUMP': { -+ var pc_add = ABC - (1 << 23) + 1; // pc is preincremented before adding -+ var pc_dst = pc + pc_add; -+ args.push(pc_dst + ' (' + (pc_add >= 0 ? '+' : '') + pc_add + ')'); -+ break; -+ } -+ default: args.push('?'); break; -+ } -+ } -+ } -+ if (op.flags) { -+ for (j = 0, m = op.flags.length; j < m; j++) { -+ if (ins & op.flags[j].mask) { -+ comments.push(op.flags[j].name); -+ } -+ } -+ } -+ -+ if (args.length > 0) { -+ str = sprintf('%05d %08x %-12s %s', pc, ins, op.name, args.join(', ')); -+ } else { -+ str = sprintf('%05d %08x %-12s', pc, ins, op.name); -+ } -+ if (comments.length > 0) { -+ str = sprintf('%-44s ; %s', str, comments.join(', ')); -+ } -+ -+ res.push({ -+ str: str, -+ ins: ins -+ }); -+ } -+ -+ return res; -+}; -+ -+Debugger.prototype.uiMessage = function (type, val) { -+ var msg; -+ if (typeof type === 'object') { -+ msg = type; -+ } else if (typeof type === 'string') { -+ msg = { type: type, message: val }; -+ } else { -+ throw new TypeError('invalid ui message: ' + type); -+ } -+ this.messageLines.push(msg); -+ while (this.messageLines.length > this.messageScrollBack) { -+ this.messageLines.shift(); -+ } -+ this.emit('ui-message-update'); // just trigger a sync, gets rate limited -+}; -+ -+Debugger.prototype.sendRequest = function (msg) { -+ var _this = this; -+ return new Promise(function (resolve, reject) { -+ var dvals = []; -+ var dval; -+ var data; -+ var i; -+ -+ if (!_this.attached || !_this.handshook || !_this.reqQueue || !_this.targetStream) { -+ throw new Error('invalid state for sendRequest'); -+ } -+ -+ for (i = 0; i < msg.length; i++) { -+ try { -+ dval = formatDebugValue(msg[i]); -+ } catch (e) { -+ console.log('Failed to format dvalue, dropping connection: ' + e); -+ console.log(e.stack || e); -+ _this.targetStream.destroy(); -+ throw new Error('failed to format dvalue'); -+ } -+ dvals.push(dval); -+ } -+ -+ data = Buffer.concat(dvals); -+ -+ _this.targetStream.write(data); -+ _this.outputPassThroughStream.write(data); // stats and dumping -+ -+ if (optLogMessages) { -+ console.log('Request ' + prettyDebugCommand(msg[1]) + ': ' + prettyDebugMessage(msg)); -+ } -+ -+ if (!_this.reqQueue) { -+ throw new Error('no reqQueue'); -+ } -+ -+ _this.reqQueue.push({ -+ reqMsg: msg, -+ reqCmd: msg[1], -+ resolveCb: resolve, -+ rejectCb: reject -+ }); -+ }); -+}; -+ -+Debugger.prototype.sendBasicInfoRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_BASICINFO, DVAL_EOM ]).then(function (msg) { -+ _this.dukVersion = msg[1]; -+ _this.dukGitDescribe = msg[2]; -+ _this.targetInfo = msg[3]; -+ _this.endianness = { 1: 'little', 2: 'mixed', 3: 'big' }[msg[4]] || 'unknown'; -+ _this.emit('basic-info-update'); -+ return msg; -+ }); -+}; -+ -+Debugger.prototype.sendGetVarRequest = function (varname, level) { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_GETVAR, (typeof level === 'number' ? level : -1), varname, DVAL_EOM ]).then(function (msg) { -+ return { found: msg[1] === 1, value: msg[2] }; -+ }); -+}; -+ -+Debugger.prototype.sendPutVarRequest = function (varname, varvalue, level) { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_PUTVAR, (typeof level === 'number' ? level : -1), varname, varvalue, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendInvalidCommandTestRequest = function () { -+ // Intentional invalid command -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, 0xdeadbeef, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendStatusRequest = function () { -+ // Send a status request to trigger a status notify, result is ignored: -+ // target sends a status notify instead of a meaningful reply -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_TRIGGERSTATUS, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendBreakpointListRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_LISTBREAK, DVAL_EOM ]).then(function (msg) { -+ var i, n; -+ var breakpts = []; -+ -+ for (i = 1, n = msg.length - 1; i < n; i += 2) { -+ breakpts.push({ fileName: msg[i], lineNumber: msg[i + 1] }); -+ } -+ -+ _this.breakpoints = breakpts; -+ _this.emit('breakpoints-update'); -+ return msg; -+ }); -+}; -+ -+Debugger.prototype.sendGetLocalsRequest = function (level) { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_GETLOCALS, (typeof level === 'number' ? level : -1), DVAL_EOM ]).then(function (msg) { -+ var i; -+ var locals = []; -+ -+ for (i = 1; i <= msg.length - 2; i += 2) { -+ // XXX: do pretty printing in debug client for now -+ locals.push({ key: msg[i], value: prettyUiDebugValue(msg[i + 1], LOCALS_CLIPLEN) }); -+ } -+ -+ _this.locals = locals; -+ _this.emit('locals-update'); -+ return msg; -+ }); -+}; -+ -+Debugger.prototype.sendGetCallStackRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_GETCALLSTACK, DVAL_EOM ]).then(function (msg) { -+ var i; -+ var stack = []; -+ -+ for (i = 1; i + 3 <= msg.length - 1; i += 4) { -+ stack.push({ -+ fileName: msg[i], -+ funcName: msg[i + 1], -+ lineNumber: msg[i + 2], -+ pc: msg[i + 3] -+ }); -+ } -+ -+ _this.callstack = stack; -+ _this.emit('callstack-update'); -+ return msg; -+ }); -+}; -+ -+Debugger.prototype.sendStepIntoRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_STEPINTO, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendStepOverRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_STEPOVER, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendStepOutRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_STEPOUT, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendPauseRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_PAUSE, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendResumeRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_RESUME, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendEvalRequest = function (evalInput, level) { -+ var _this = this; -+ // Use explicit level if given. If no level is given, use null if the call -+ // stack is empty, -1 otherwise. This works well when we're paused and the -+ // callstack information is not liable to change before we do an Eval. -+ if (typeof level !== 'number') { -+ level = this.callstack && this.callstack.length > 0 ? -1 : null; -+ } -+ return this.sendRequest([ DVAL_REQ, CMD_EVAL, level, evalInput, DVAL_EOM ]).then(function (msg) { -+ return { error: msg[1] === 1 /*error*/, value: msg[2] }; -+ }); -+}; -+ -+Debugger.prototype.sendDetachRequest = function () { -+ var _this = this; -+ return this.sendRequest([ DVAL_REQ, CMD_DETACH, DVAL_EOM ]); -+}; -+ -+Debugger.prototype.sendDumpHeapRequest = function () { -+ var _this = this; -+ -+ return this.sendRequest([ DVAL_REQ, CMD_DUMPHEAP, DVAL_EOM ]).then(function (msg) { -+ var res = {}; -+ var objs = []; -+ var i, j, n, m, o, prop; -+ -+ res.type = 'heapDump'; -+ res.heapObjects = objs; -+ -+ for (i = 1, n = msg.length - 1; i < n; /*nop*/) { -+ o = {}; -+ o.ptr = msg[i++]; -+ o.type = msg[i++]; -+ o.flags = msg[i++] >>> 0; /* unsigned */ -+ o.refc = msg[i++]; -+ -+ if (o.type === DUK_HTYPE_STRING) { -+ o.blen = msg[i++]; -+ o.clen = msg[i++]; -+ o.hash = msg[i++] >>> 0; /* unsigned */ -+ o.data = msg[i++]; -+ } else if (o.type === DUK_HTYPE_BUFFER) { -+ o.len = msg[i++]; -+ o.data = msg[i++]; -+ } else if (o.type === DUK_HTYPE_OBJECT) { -+ o['class'] = msg[i++]; -+ o.proto = msg[i++]; -+ o.esize = msg[i++]; -+ o.enext = msg[i++]; -+ o.asize = msg[i++]; -+ o.hsize = msg[i++]; -+ o.props = []; -+ for (j = 0, m = o.enext; j < m; j++) { -+ prop = {}; -+ prop.flags = msg[i++]; -+ prop.key = msg[i++]; -+ prop.accessor = (msg[i++] == 1); -+ if (prop.accessor) { -+ prop.getter = msg[i++]; -+ prop.setter = msg[i++]; -+ } else { -+ prop.value = msg[i++]; -+ } -+ o.props.push(prop); -+ } -+ o.array = []; -+ for (j = 0, m = o.asize; j < m; j++) { -+ prop = {}; -+ prop.value = msg[i++]; -+ o.array.push(prop); -+ } -+ } else { -+ console.log('invalid htype: ' + o.type + ', disconnect'); -+ _this.disconnectDebugger(); -+ throw new Error('invalid htype'); -+ return; -+ } -+ -+ objs.push(o); -+ } -+ -+ return res; -+ }); -+}; -+ -+Debugger.prototype.sendGetBytecodeRequest = function () { -+ var _this = this; -+ -+ return this.sendRequest([ DVAL_REQ, CMD_GETBYTECODE, -1 /* level; could be other than -1 too */, DVAL_EOM ]).then(function (msg) { -+ var idx = 1; -+ var nconst; -+ var nfunc; -+ var val; -+ var buf; -+ var i, n; -+ var consts = []; -+ var funcs = []; -+ var bcode; -+ var preformatted; -+ var ret; -+ var idxPreformattedInstructions; -+ -+ //console.log(JSON.stringify(msg)); -+ -+ nconst = msg[idx++]; -+ for (i = 0; i < nconst; i++) { -+ val = msg[idx++]; -+ consts.push(val); -+ } -+ -+ nfunc = msg[idx++]; -+ for (i = 0; i < nfunc; i++) { -+ val = msg[idx++]; -+ funcs.push(val); -+ } -+ val = msg[idx++]; -+ -+ // Right now bytecode is a string containing a direct dump of the -+ // bytecode in target endianness. Decode here so that the web UI -+ // doesn't need to. -+ -+ buf = new Buffer(val.length); -+ writeDebugStringToBuffer(val, buf, 0); -+ bcode = _this.decodeBytecodeFromBuffer(buf, consts, funcs); -+ -+ preformatted = []; -+ consts.forEach(function (v, i) { -+ preformatted.push('; c' + i + ' ' + JSON.stringify(v)); -+ }); -+ preformatted.push(''); -+ idxPreformattedInstructions = preformatted.length; -+ bcode.forEach(function (v) { -+ preformatted.push(v.str); -+ }); -+ preformatted = preformatted.join('\n') + '\n'; -+ -+ ret = { -+ constants: consts, -+ functions: funcs, -+ bytecode: bcode, -+ preformatted: preformatted, -+ idxPreformattedInstructions: idxPreformattedInstructions -+ }; -+ -+ return ret; -+ }); -+}; -+ -+Debugger.prototype.changeBreakpoint = function (fileName, lineNumber, mode) { -+ var _this = this; -+ -+ return this.sendRequest([ DVAL_REQ, CMD_LISTBREAK, DVAL_EOM ]).then(function (msg) { -+ var i, n; -+ var breakpts = []; -+ var deleted = false; -+ -+ // Up-to-date list of breakpoints on target -+ for (i = 1, n = msg.length - 1; i < n; i += 2) { -+ breakpts.push({ fileName: msg[i], lineNumber: msg[i + 1] }); -+ } -+ -+ // Delete matching breakpoints in reverse order so that indices -+ // remain valid. We do this for all operations so that duplicates -+ // are eliminated if present. -+ for (i = breakpts.length - 1; i >= 0; i--) { -+ var bp = breakpts[i]; -+ if (mode === 'deleteall' || (bp.fileName === fileName && bp.lineNumber === lineNumber)) { -+ deleted = true; -+ _this.sendRequest([ DVAL_REQ, CMD_DELBREAK, i, DVAL_EOM ], function (msg) { -+ // nop -+ }, function (err) { -+ // nop -+ }); -+ } -+ } -+ -+ // Technically we should wait for each delbreak reply but because -+ // target processes the requests in order, it doesn't matter. -+ if ((mode === 'add') || (mode === 'toggle' && !deleted)) { -+ _this.sendRequest([ DVAL_REQ, CMD_ADDBREAK, fileName, lineNumber, DVAL_EOM ], function (msg) { -+ // nop -+ }, function (err) { -+ _this.uiMessage('debugger-info', 'Failed to add breakpoint: ' + err); -+ }); -+ } -+ -+ // Read final, effective breakpoints from the target -+ _this.sendBreakpointListRequest(); -+ }); -+}; -+ -+Debugger.prototype.disconnectDebugger = function () { -+ if (this.targetStream) { -+ // We require a destroy() method from the actual target stream -+ this.targetStream.destroy(); -+ this.targetStream = null; -+ } -+ if (this.inputParser) { -+ this.inputParser.close(); -+ this.inputParser = null; -+ } -+ if (this.outputPassThroughStream) { -+ // There is no close() or destroy() for a passthrough stream, so just -+ // close the outputParser which will cancel timers etc. -+ } -+ if (this.outputParser) { -+ this.outputParser.close(); -+ this.outputParser = null; -+ } -+ -+ this.attached = false; -+ this.handshook = false; -+ this.reqQueue = null; -+ this.execStatus = { -+ attached: false, -+ state: 'detached', -+ fileName: '', -+ funcName: '', -+ line: 0, -+ pc: 0 -+ }; -+}; -+ -+Debugger.prototype.connectDebugger = function () { -+ var _this = this; -+ -+ this.disconnectDebugger(); // close previous target connection -+ -+ // CUSTOMTRANSPORT: to use a custom transport, change this.targetStream to -+ // use your custom transport. -+ -+ console.log('Connecting to ' + optTargetHost + ':' + optTargetPort + '...'); -+ this.targetStream = new net.Socket(); -+ this.targetStream.connect(optTargetPort, optTargetHost, function () { -+ console.log('Debug transport connected'); -+ _this.attached = true; -+ _this.reqQueue = []; -+ _this.uiMessage('debugger-info', 'Debug transport connected'); -+ }); -+ -+ this.inputParser = new DebugProtocolParser( -+ this.targetStream, -+ null, -+ optDumpDebugRead, -+ optDumpDebugPretty, -+ optDumpDebugPretty ? 'Recv: ' : null, -+ null, -+ null // console logging is done at a higher level to match request/response -+ ); -+ -+ // Use a PassThrough stream to debug dump and get stats for output messages. -+ // Simply write outgoing data to both the targetStream and this passthrough -+ // separately. -+ this.outputPassThroughStream = stream.PassThrough(); -+ this.outputParser = new DebugProtocolParser( -+ this.outputPassThroughStream, -+ 1, -+ optDumpDebugWrite, -+ optDumpDebugPretty, -+ optDumpDebugPretty ? 'Send: ' : null, -+ null, -+ null // console logging is done at a higher level to match request/response -+ ); -+ -+ this.inputParser.on('transport-close', function () { -+ _this.uiMessage('debugger-info', 'Debug transport closed'); -+ _this.disconnectDebugger(); -+ _this.emit('exec-status-update'); -+ _this.emit('detached'); -+ }); -+ -+ this.inputParser.on('transport-error', function (err) { -+ _this.uiMessage('debugger-info', 'Debug transport error: ' + err); -+ _this.disconnectDebugger(); -+ }); -+ -+ this.inputParser.on('protocol-version', function (msg) { -+ var ver = msg.protocolVersion; -+ console.log('Debug version identification:', msg.versionIdentification); -+ _this.protocolVersion = ver; -+ _this.uiMessage('debugger-info', 'Debug version identification: ' + msg.versionIdentification); -+ if (ver !== SUPPORTED_DEBUG_PROTOCOL_VERSION) { -+ console.log('Unsupported debug protocol version (got ' + ver + ', support ' + SUPPORTED_DEBUG_PROTOCOL_VERSION + ')'); -+ _this.uiMessage('debugger-info', 'Protocol version ' + ver + ' unsupported, dropping connection'); -+ _this.targetStream.destroy(); -+ } else { -+ _this.uiMessage('debugger-info', 'Debug protocol version: ' + ver); -+ _this.handshook = true; -+ _this.execStatus = { -+ attached: true, -+ state: 'attached', -+ fileName: '', -+ funcName: '', -+ line: 0, -+ pc: 0 -+ }; -+ _this.emit('exec-status-update'); -+ _this.emit('attached'); // inform web UI -+ -+ // Fetch basic info right away -+ _this.sendBasicInfoRequest(); -+ } -+ }); -+ -+ this.inputParser.on('debug-message', function (msg) { -+ _this.processDebugMessage(msg); -+ }); -+ -+ this.inputParser.on('stats-update', function () { -+ _this.stats.rxBytes = this.bytes; -+ _this.stats.rxDvalues = this.dvalues; -+ _this.stats.rxMessages = this.messages; -+ _this.stats.rxBytesPerSec = this.bytesPerSec; -+ _this.emit('debug-stats-update'); -+ }); -+ -+ this.outputParser.on('stats-update', function () { -+ _this.stats.txBytes = this.bytes; -+ _this.stats.txDvalues = this.dvalues; -+ _this.stats.txMessages = this.messages; -+ _this.stats.txBytesPerSec = this.bytesPerSec; -+ _this.emit('debug-stats-update'); -+ }); -+}; -+ -+Debugger.prototype.processDebugMessage = function (msg) { -+ var req; -+ var prevState, newState; -+ var err; -+ -+ if (msg[0] === DVAL_REQ) { -+ // No actual requests sent by the target right now (just notifys). -+ console.log('Unsolicited reply message, dropping connection: ' + prettyDebugMessage(msg)); -+ } else if (msg[0] === DVAL_REP) { -+ if (this.reqQueue.length <= 0) { -+ console.log('Unsolicited reply message, dropping connection: ' + prettyDebugMessage(msg)); -+ this.targetStream.destroy(); -+ } -+ req = this.reqQueue.shift(); -+ -+ if (optLogMessages) { -+ console.log('Reply for ' + prettyDebugCommand(req.reqCmd) + ': ' + prettyDebugMessage(msg)); -+ } -+ -+ if (req.resolveCb) { -+ req.resolveCb(msg); -+ } else { -+ // nop: no callback -+ } -+ } else if (msg[0] === DVAL_ERR) { -+ if (this.reqQueue.length <= 0) { -+ console.log('Unsolicited error message, dropping connection: ' + prettyDebugMessage(msg)); -+ this.targetStream.destroy(); -+ } -+ err = new Error(String(msg[2]) + ' (code ' + String(msg[1]) + ')'); -+ err.errorCode = msg[1] || 0; -+ req = this.reqQueue.shift(); -+ -+ if (optLogMessages) { -+ console.log('Error for ' + prettyDebugCommand(req.reqCmd) + ': ' + prettyDebugMessage(msg)); -+ } -+ -+ if (req.rejectCb) { -+ req.rejectCb(err); -+ } else { -+ // nop: no callback -+ } -+ } else if (msg[0] === DVAL_NFY) { -+ if (optLogMessages) { -+ console.log('Notify ' + prettyDebugCommand(msg[1]) + ': ' + prettyDebugMessage(msg)); -+ } -+ -+ if (msg[1] === CMD_STATUS) { -+ prevState = this.execStatus.state; -+ newState = msg[2] === 0 ? 'running' : 'paused'; -+ this.execStatus = { -+ attached: true, -+ state: newState, -+ fileName: msg[3], -+ funcName: msg[4], -+ line: msg[5], -+ pc: msg[6] -+ }; -+ -+ if (prevState !== newState && newState === 'paused') { -+ // update run state now that we're paused -+ this.sendBreakpointListRequest(); -+ this.sendGetLocalsRequest(); -+ this.sendGetCallStackRequest(); -+ } -+ -+ this.emit('exec-status-update'); -+ } else if (msg[1] === CMD_THROW) { -+ this.uiMessage({ type: 'throw', fatal: msg[2], message: (msg[2] ? 'UNCAUGHT: ' : 'THROW: ') + prettyUiStringUnquoted(msg[3], UI_MESSAGE_CLIPLEN), fileName: msg[4], lineNumber: msg[5] }); -+ } else if (msg[1] === CMD_DETACHING) { -+ this.uiMessage({ type: 'detaching', reason: msg[2], message: 'DETACH: ' + (msg.length >= 5 ? prettyUiStringUnquoted(msg[3]) : 'detaching') }); -+ } else { -+ // Ignore unknown notify messages -+ console.log('Unknown notify, ignoring: ' + prettyDebugMessage(msg)); -+ -+ //this.targetStream.destroy(); -+ } -+ } else { -+ console.log('Invalid initial dvalue, dropping connection: ' + prettyDebugMessage(msg)); -+ this.targetStream.destroy(); -+ } -+}; -+ -+Debugger.prototype.run = function () { -+ var _this = this; -+ -+ // Initial debugger connection -+ -+ this.connectDebugger(); -+ -+ // Poll various state items when running -+ -+ var sendRound = 0; -+ var statusPending = false; -+ var bplistPending = false; -+ var localsPending = false; -+ var callStackPending = false; -+ -+ setInterval(function () { -+ if (_this.execStatus.state !== 'running') { -+ return; -+ } -+ -+ // Could also check for an empty request queue, but that's probably -+ // too strict? -+ -+ // Pending flags are used to avoid requesting the same thing twice -+ // while a previous request is pending. The flag-based approach is -+ // quite awkward. Rework to use promises. -+ -+ switch (sendRound) { -+ case 0: -+ if (!statusPending) { -+ statusPending = true; -+ _this.sendStatusRequest().finally(function () { statusPending = false; }); -+ } -+ break; -+ case 1: -+ if (!bplistPending) { -+ bplistPending = true; -+ _this.sendBreakpointListRequest().finally(function () { bplistPending = false; }); -+ } -+ break; -+ case 2: -+ if (!localsPending) { -+ localsPending = true; -+ _this.sendGetLocalsRequest().finally(function () { localsPending = false; }); -+ } -+ break; -+ case 3: -+ if (!callStackPending) { -+ callStackPending = true; -+ _this.sendGetCallStackRequest().finally(function () { callStackPending = false; }); -+ } -+ break; -+ } -+ sendRound = (sendRound + 1) % 4; -+ }, 500); -+}; -+ -+/* -+ * Express setup and socket.io -+ */ -+ -+function DebugWebServer() { -+ this.dbg = null; // debugger singleton -+ this.socket = null; // current socket (or null) -+ this.keepaliveTimer = null; -+ this.uiMessageLimiter = null; -+ this.cachedJson = {}; // cache to avoid resending identical data -+ this.sourceFileManager = new SourceFileManager(optSourceSearchDirs); -+ this.sourceFileManager.scan(); -+} -+ -+DebugWebServer.prototype.handleSourcePost = function (req, res) { -+ var fileName = req.body && req.body.fileName; -+ var fileData; -+ -+ console.log('Source request: ' + fileName); -+ -+ if (typeof fileName !== 'string') { -+ res.status(500).send('invalid request'); -+ return; -+ } -+ fileData = this.sourceFileManager.search(fileName, optSourceSearchDirs); -+ if (typeof fileData !== 'string') { -+ res.status(404).send('not found'); -+ return; -+ } -+ res.status(200).send(fileData); // UTF-8 -+}; -+ -+DebugWebServer.prototype.handleSourceListPost = function (req, res) { -+ console.log('Source list request'); -+ -+ var files = this.sourceFileManager.getFiles(); -+ res.header('Content-Type', 'application/json'); -+ res.status(200).json(files); -+}; -+ -+DebugWebServer.prototype.handleHeapDumpGet = function (req, res) { -+ console.log('Heap dump get'); -+ -+ this.dbg.sendDumpHeapRequest().then(function (val) { -+ res.header('Content-Type', 'application/json'); -+ //res.status(200).json(val); -+ res.status(200).send(JSON.stringify(val, null, 4)); -+ }).catch(function (err) { -+ res.status(500).send('Failed to get heap dump: ' + (err.stack || err)); -+ }); -+}; -+ -+DebugWebServer.prototype.run = function () { -+ var _this = this; -+ -+ var express = require('express'); -+ var bodyParser = require('body-parser'); -+ var app = express(); -+ var http = require('http').Server(app); -+ var io = require('socket.io')(http); -+ -+ app.use(bodyParser.json()); -+ app.post('/source', this.handleSourcePost.bind(this)); -+ app.post('/sourceList', this.handleSourceListPost.bind(this)); -+ app.get('/heapDump.json', this.handleHeapDumpGet.bind(this)); -+ app.use('/', express.static(__dirname + '/static')); -+ -+ http.listen(optHttpPort, function () { -+ console.log('Listening on *:' + optHttpPort); -+ }); -+ -+ io.on('connection', this.handleNewSocketIoConnection.bind(this)); -+ -+ this.dbg.on('attached', function () { -+ console.log('Debugger attached'); -+ }); -+ -+ this.dbg.on('detached', function () { -+ console.log('Debugger detached'); -+ }); -+ -+ this.dbg.on('debug-stats-update', function () { -+ _this.debugStatsLimiter.trigger(); -+ }); -+ -+ this.dbg.on('ui-message-update', function () { -+ // Explicit rate limiter because this is a source of a lot of traffic. -+ _this.uiMessageLimiter.trigger(); -+ }); -+ -+ this.dbg.on('basic-info-update', function () { -+ _this.emitBasicInfo(); -+ }); -+ -+ this.dbg.on('breakpoints-update', function () { -+ _this.emitBreakpoints(); -+ }); -+ -+ this.dbg.on('exec-status-update', function () { -+ // Explicit rate limiter because this is a source of a lot of traffic. -+ _this.execStatusLimiter.trigger(); -+ }); -+ -+ this.dbg.on('locals-update', function () { -+ _this.emitLocals(); -+ }); -+ -+ this.dbg.on('callstack-update', function () { -+ _this.emitCallStack(); -+ }); -+ -+ this.uiMessageLimiter = new RateLimited(10, 1000, this.uiMessageLimiterCallback.bind(this)); -+ this.execStatusLimiter = new RateLimited(50, 500, this.execStatusLimiterCallback.bind(this)); -+ this.debugStatsLimiter = new RateLimited(1, 2000, this.debugStatsLimiterCallback.bind(this)); -+ -+ this.keepaliveTimer = setInterval(this.emitKeepalive.bind(this), 30000); -+}; -+ -+DebugWebServer.prototype.handleNewSocketIoConnection = function (socket) { -+ var _this = this; -+ -+ console.log('Socket.io connected'); -+ if (this.socket) { -+ console.log('Closing previous socket.io socket'); -+ this.socket.emit('replaced'); -+ } -+ this.socket = socket; -+ -+ this.emitKeepalive(); -+ -+ socket.on('disconnect', function () { -+ console.log('Socket.io disconnected'); -+ if (_this.socket === socket) { -+ _this.socket = null; -+ } -+ }); -+ -+ socket.on('keepalive', function (msg) { -+ // nop -+ }); -+ -+ socket.on('attach', function (msg) { -+ if (_this.dbg.targetStream) { -+ console.log('Attach request when debugger already has a connection, ignoring'); -+ } else { -+ _this.dbg.connectDebugger(); -+ } -+ }); -+ -+ socket.on('detach', function (msg) { -+ // Try to detach cleanly, timeout if no response -+ Promise.any([ -+ _this.dbg.sendDetachRequest(), -+ Promise.delay(3000) -+ ]).finally(function () { -+ _this.dbg.disconnectDebugger(); -+ }); -+ }); -+ -+ socket.on('stepinto', function (msg) { -+ _this.dbg.sendStepIntoRequest(); -+ }); -+ -+ socket.on('stepover', function (msg) { -+ _this.dbg.sendStepOverRequest(); -+ }); -+ -+ socket.on('stepout', function (msg) { -+ _this.dbg.sendStepOutRequest(); -+ }); -+ -+ socket.on('pause', function (msg) { -+ _this.dbg.sendPauseRequest(); -+ }); -+ -+ socket.on('resume', function (msg) { -+ _this.dbg.sendResumeRequest(); -+ }); -+ -+ socket.on('eval', function (msg) { -+ // msg.input is a proper Unicode strings here, and needs to be -+ // converted into a protocol string (U+0000...U+00FF). -+ var input = stringToDebugString(msg.input); -+ _this.dbg.sendEvalRequest(input, msg.level).then(function (v) { -+ socket.emit('eval-result', { error: v.error, result: prettyUiDebugValue(v.value, EVAL_CLIPLEN) }); -+ }); -+ -+ // An eval call quite possibly changes the local variables so always -+ // re-read locals afterwards. We don't need to wait for Eval to -+ // complete here; the requests will pipeline automatically and be -+ // executed in order. -+ -+ // XXX: move this to the web UI so that the UI can control what -+ // locals are listed (or perhaps show locals for all levels with -+ // an expandable tree view). -+ _this.dbg.sendGetLocalsRequest(); -+ }); -+ -+ socket.on('getvar', function (msg) { -+ // msg.varname is a proper Unicode strings here, and needs to be -+ // converted into a protocol string (U+0000...U+00FF). -+ var varname = stringToDebugString(msg.varname); -+ _this.dbg.sendGetVarRequest(varname, msg.level) -+ .then(function (v) { -+ socket.emit('getvar-result', { found: v.found, result: prettyUiDebugValue(v.value, GETVAR_CLIPLEN) }); -+ }); -+ }); -+ -+ socket.on('putvar', function (msg) { -+ // msg.varname and msg.varvalue are proper Unicode strings here, they -+ // need to be converted into protocol strings (U+0000...U+00FF). -+ var varname = stringToDebugString(msg.varname); -+ var varvalue = msg.varvalue; -+ -+ // varvalue is JSON parsed by the web UI for now, need special string -+ // encoding here. -+ if (typeof varvalue === 'string') { -+ varvalue = stringToDebugString(msg.varvalue); -+ } -+ -+ _this.dbg.sendPutVarRequest(varname, varvalue, msg.level) -+ .then(function (v) { -+ console.log('putvar done'); // XXX: signal success to UI? -+ }); -+ -+ // A PutVar call quite possibly changes the local variables so always -+ // re-read locals afterwards. We don't need to wait for PutVar to -+ // complete here; the requests will pipeline automatically and be -+ // executed in order. -+ -+ // XXX: make the client do this? -+ _this.dbg.sendGetLocalsRequest(); -+ }); -+ -+ socket.on('add-breakpoint', function (msg) { -+ _this.dbg.changeBreakpoint(msg.fileName, msg.lineNumber, 'add'); -+ }); -+ -+ socket.on('delete-breakpoint', function (msg) { -+ _this.dbg.changeBreakpoint(msg.fileName, msg.lineNumber, 'delete'); -+ }); -+ -+ socket.on('toggle-breakpoint', function (msg) { -+ _this.dbg.changeBreakpoint(msg.fileName, msg.lineNumber, 'toggle'); -+ }); -+ -+ socket.on('delete-all-breakpoints', function (msg) { -+ _this.dbg.changeBreakpoint(null, null, 'deleteall'); -+ }); -+ -+ socket.on('get-bytecode', function (msg) { -+ _this.dbg.sendGetBytecodeRequest().then(function (res) { -+ socket.emit('bytecode', res); -+ }); -+ }); -+ -+ // Resend all debugger state for new client -+ this.cachedJson = {}; // clear client state cache -+ this.emitBasicInfo(); -+ this.emitStats(); -+ this.emitExecStatus(); -+ this.emitUiMessages(); -+ this.emitBreakpoints(); -+ this.emitCallStack(); -+ this.emitLocals(); -+}; -+ -+// Check if 'msg' would encode to the same JSON which was previously sent -+// to the web client. The caller then avoid resending unnecessary stuff. -+DebugWebServer.prototype.cachedJsonCheck = function (cacheKey, msg) { -+ var newJson = JSON.stringify(msg); -+ if (this.cachedJson[cacheKey] === newJson) { -+ return true; // cached -+ } -+ this.cachedJson[cacheKey] = newJson; -+ return false; // not cached, send (cache already updated) -+}; -+ -+DebugWebServer.prototype.uiMessageLimiterCallback = function () { -+ this.emitUiMessages(); -+}; -+ -+DebugWebServer.prototype.execStatusLimiterCallback = function () { -+ this.emitExecStatus(); -+}; -+ -+DebugWebServer.prototype.debugStatsLimiterCallback = function () { -+ this.emitStats(); -+}; -+ -+DebugWebServer.prototype.emitKeepalive = function () { -+ if (!this.socket) { return; } -+ -+ this.socket.emit('keepalive', { nodeVersion: process.version }); -+}; -+ -+DebugWebServer.prototype.emitBasicInfo = function () { -+ if (!this.socket) { return; } -+ -+ var newMsg = { -+ duk_version: this.dbg.dukVersion, -+ duk_git_describe: this.dbg.dukGitDescribe, -+ target_info: this.dbg.targetInfo, -+ endianness: this.dbg.endianness -+ }; -+ if (this.cachedJsonCheck('basic-info', newMsg)) { -+ return; -+ } -+ this.socket.emit('basic-info', newMsg); -+}; -+ -+DebugWebServer.prototype.emitStats = function () { -+ if (!this.socket) { return; } -+ -+ this.socket.emit('debug-stats', this.dbg.stats); -+}; -+ -+DebugWebServer.prototype.emitExecStatus = function () { -+ if (!this.socket) { return; } -+ -+ var newMsg = this.dbg.execStatus; -+ if (this.cachedJsonCheck('exec-status', newMsg)) { -+ return; -+ } -+ this.socket.emit('exec-status', newMsg); -+}; -+ -+DebugWebServer.prototype.emitUiMessages = function () { -+ if (!this.socket) { return; } -+ -+ var newMsg = this.dbg.messageLines; -+ if (this.cachedJsonCheck('output-lines', newMsg)) { -+ return; -+ } -+ this.socket.emit('output-lines', newMsg); -+}; -+ -+DebugWebServer.prototype.emitBreakpoints = function () { -+ if (!this.socket) { return; } -+ -+ var newMsg = { breakpoints: this.dbg.breakpoints }; -+ if (this.cachedJsonCheck('breakpoints', newMsg)) { -+ return; -+ } -+ this.socket.emit('breakpoints', newMsg); -+}; -+ -+DebugWebServer.prototype.emitCallStack = function () { -+ if (!this.socket) { return; } -+ -+ var newMsg = { callstack: this.dbg.callstack }; -+ if (this.cachedJsonCheck('callstack', newMsg)) { -+ return; -+ } -+ this.socket.emit('callstack', newMsg); -+}; -+ -+DebugWebServer.prototype.emitLocals = function () { -+ if (!this.socket) { return; } -+ -+ var newMsg = { locals: this.dbg.locals }; -+ if (this.cachedJsonCheck('locals', newMsg)) { -+ return; -+ } -+ this.socket.emit('locals', newMsg); -+}; -+ -+/* -+ * JSON debug proxy -+ */ -+ -+function DebugProxy(serverPort) { -+ this.serverPort = serverPort; -+ this.server = null; -+ this.socket = null; -+ this.targetStream = null; -+ this.inputParser = null; -+ -+ // preformatted dvalues -+ this.dval_eom = formatDebugValue(DVAL_EOM); -+ this.dval_req = formatDebugValue(DVAL_REQ); -+ this.dval_rep = formatDebugValue(DVAL_REP); -+ this.dval_nfy = formatDebugValue(DVAL_NFY); -+ this.dval_err = formatDebugValue(DVAL_ERR); -+} -+ -+DebugProxy.prototype.determineCommandNumber = function (cmdName, cmdNumber) { -+ var ret; -+ if (typeof cmdName === 'string') { -+ ret = debugCommandNumbers[cmdName]; -+ } else if (typeof cmdName === 'number') { -+ ret = cmdName; -+ } -+ ret = ret || cmdNumber; -+ if (typeof ret !== 'number') { -+ throw Error('cannot figure out command number for "' + cmdName + '" (' + cmdNumber + ')'); -+ } -+ return ret; -+}; -+ -+DebugProxy.prototype.commandNumberToString = function (id) { -+ return debugCommandNames[id] || String(id); -+}; -+ -+DebugProxy.prototype.formatDvalues = function (args) { -+ if (!args) { -+ return []; -+ } -+ return args.map(function (v) { -+ return formatDebugValue(v); -+ }); -+}; -+ -+DebugProxy.prototype.writeJson = function (val) { -+ this.socket.write(JSON.stringify(val) + '\n'); -+}; -+ -+DebugProxy.prototype.writeJsonSafe = function (val) { -+ try { -+ this.writeJson(val); -+ } catch (e) { -+ console.log('Failed to write JSON in writeJsonSafe, ignoring: ' + e); -+ } -+}; -+ -+DebugProxy.prototype.disconnectJsonClient = function () { -+ if (this.socket) { -+ this.socket.destroy(); -+ this.socket = null; -+ } -+}; -+ -+DebugProxy.prototype.disconnectTarget = function () { -+ if (this.inputParser) { -+ this.inputParser.close(); -+ this.inputParser = null; -+ } -+ if (this.targetStream) { -+ this.targetStream.destroy(); -+ this.targetStream = null; -+ } -+}; -+ -+DebugProxy.prototype.run = function () { -+ var _this = this; -+ -+ console.log('Waiting for client connections on port ' + this.serverPort); -+ this.server = net.createServer(function (socket) { -+ console.log('JSON proxy client connected'); -+ -+ _this.disconnectJsonClient(); -+ _this.disconnectTarget(); -+ -+ // A byline-parser is simple and good enough for now (assume -+ // compact JSON with no newlines). -+ var socketByline = byline(socket); -+ _this.socket = socket; -+ -+ socketByline.on('data', function (line) { -+ try { -+ // console.log('Received json proxy input line: ' + line.toString('utf8')); -+ var msg = JSON.parse(line.toString('utf8')); -+ var first_dval; -+ var args_dvalues = _this.formatDvalues(msg.args); -+ var last_dval = _this.dval_eom; -+ var cmd; -+ -+ if (msg.request) { -+ // "request" can be a string or "true" -+ first_dval = _this.dval_req; -+ cmd = _this.determineCommandNumber(msg.request, msg.command); -+ } else if (msg.reply) { -+ first_dval = _this.dval_rep; -+ } else if (msg.notify) { -+ // "notify" can be a string or "true" -+ first_dval = _this.dval_nfy; -+ cmd = _this.determineCommandNumber(msg.notify, msg.command); -+ } else if (msg.error) { -+ first_dval = _this.dval_err; -+ } else { -+ throw new Error('Invalid input JSON message: ' + JSON.stringify(msg)); -+ } -+ -+ _this.targetStream.write(first_dval); -+ if (cmd) { -+ _this.targetStream.write(formatDebugValue(cmd)); -+ } -+ args_dvalues.forEach(function (v) { -+ _this.targetStream.write(v); -+ }); -+ _this.targetStream.write(last_dval); -+ } catch (e) { -+ console.log(e); -+ -+ _this.writeJsonSafe({ -+ notify: '_Error', -+ args: [ 'Failed to handle input json message: ' + e ] -+ }); -+ -+ _this.disconnectJsonClient(); -+ _this.disconnectTarget(); -+ } -+ }); -+ -+ _this.connectToTarget(); -+ }).listen(this.serverPort); -+}; -+ -+DebugProxy.prototype.connectToTarget = function () { -+ var _this = this; -+ -+ console.log('Connecting to ' + optTargetHost + ':' + optTargetPort + '...'); -+ this.targetStream = new net.Socket(); -+ this.targetStream.connect(optTargetPort, optTargetHost, function () { -+ console.log('Debug transport connected'); -+ }); -+ -+ this.inputParser = new DebugProtocolParser( -+ this.targetStream, -+ null, -+ optDumpDebugRead, -+ optDumpDebugPretty, -+ optDumpDebugPretty ? 'Recv: ' : null, -+ null, -+ null // console logging is done at a higher level to match request/response -+ ); -+ -+ // Don't add a 'value' key to numbers. -+ this.inputParser.readableNumberValue = false; -+ -+ this.inputParser.on('transport-close', function () { -+ console.log('Debug transport closed'); -+ -+ _this.writeJsonSafe({ -+ notify: '_Disconnecting' -+ }); -+ -+ _this.disconnectJsonClient(); -+ _this.disconnectTarget(); -+ }); -+ -+ this.inputParser.on('transport-error', function (err) { -+ console.log('Debug transport error', err); -+ -+ _this.writeJsonSafe({ -+ notify: '_Error', -+ args: [ String(err) ] -+ }); -+ }); -+ -+ this.inputParser.on('protocol-version', function (msg) { -+ var ver = msg.protocolVersion; -+ console.log('Debug version identification:', msg.versionIdentification); -+ -+ _this.writeJson({ -+ notify: '_TargetConnected', -+ args: [ msg.versionIdentification ] // raw identification string -+ }); -+ -+ if (ver !== 1) { -+ console.log('Protocol version ' + ver + ' unsupported, dropping connection'); -+ } -+ }); -+ -+ this.inputParser.on('debug-message', function (msg) { -+ var t; -+ -+ //console.log(msg); -+ -+ if (typeof msg[0] !== 'object' || msg[0] === null) { -+ throw new Error('unexpected initial dvalue: ' + msg[0]); -+ } else if (msg[0].type === 'eom') { -+ throw new Error('unexpected initial dvalue: ' + msg[0]); -+ } else if (msg[0].type === 'req') { -+ if (typeof msg[1] !== 'number') { -+ throw new Error('unexpected request command number: ' + msg[1]); -+ } -+ t = { -+ request: _this.commandNumberToString(msg[1]), -+ command: msg[1], -+ args: msg.slice(2, msg.length - 1) -+ }; -+ _this.writeJson(t); -+ } else if (msg[0].type === 'rep') { -+ t = { -+ reply: true, -+ args: msg.slice(1, msg.length - 1) -+ }; -+ _this.writeJson(t); -+ } else if (msg[0].type === 'err') { -+ t = { -+ error: true, -+ args: msg.slice(1, msg.length - 1) -+ }; -+ _this.writeJson(t); -+ } else if (msg[0].type === 'nfy') { -+ if (typeof msg[1] !== 'number') { -+ throw new Error('unexpected notify command number: ' + msg[1]); -+ } -+ t = { -+ notify: _this.commandNumberToString(msg[1]), -+ command: msg[1], -+ args: msg.slice(2, msg.length - 1) -+ }; -+ _this.writeJson(t); -+ } else { -+ throw new Error('unexpected initial dvalue: ' + msg[0]); -+ } -+ }); -+ -+ this.inputParser.on('stats-update', function () { -+ }); -+}; -+ -+/* -+ * Command line parsing and initialization -+ */ -+ -+function main() { -+ console.log('((o) Duktape debugger'); -+ -+ // Parse arguments. -+ -+ var argv = require('minimist')(process.argv.slice(2)); -+ //console.dir(argv); -+ if (argv['target-host']) { -+ optTargetHost = argv['target-host']; -+ } -+ if (argv['target-port']) { -+ optTargetPort = argv['target-port']; -+ } -+ if (argv['http-port']) { -+ optHttpPort = argv['http-port']; -+ } -+ if (argv['json-proxy-port']) { -+ optJsonProxyPort = argv['json-proxy-port']; -+ } -+ if (argv['json-proxy']) { -+ optJsonProxy = argv['json-proxy']; -+ } -+ if (argv['source-dirs']) { -+ optSourceSearchDirs = argv['source-dirs'].split(path.delimiter); -+ } -+ if (argv['dump-debug-read']) { -+ optDumpDebugRead = argv['dump-debug-read']; -+ } -+ if (argv['dump-debug-write']) { -+ optDumpDebugWrite = argv['dump-debug-write']; -+ } -+ if (argv['dump-debug-pretty']) { -+ optDumpDebugPretty = argv['dump-debug-pretty']; -+ } -+ if (argv['log-messages']) { -+ optLogMessages = true; -+ } -+ -+ // Dump effective options. Also provides a list of option names. -+ -+ console.log(''); -+ console.log('Effective options:'); -+ console.log(' --target-host: ' + optTargetHost); -+ console.log(' --target-port: ' + optTargetPort); -+ console.log(' --http-port: ' + optHttpPort); -+ console.log(' --json-proxy-port: ' + optJsonProxyPort); -+ console.log(' --json-proxy: ' + optJsonProxy); -+ console.log(' --source-dirs: ' + optSourceSearchDirs.join(' ')); -+ console.log(' --dump-debug-read: ' + optDumpDebugRead); -+ console.log(' --dump-debug-write: ' + optDumpDebugWrite); -+ console.log(' --dump-debug-pretty: ' + optDumpDebugPretty); -+ console.log(' --log-messages: ' + optLogMessages); -+ console.log(''); -+ -+ // Create debugger and web UI singletons, tie them together and -+ // start them. -+ -+ if (optJsonProxy) { -+ console.log('Starting in JSON proxy mode, JSON port: ' + optJsonProxyPort); -+ -+ var prx = new DebugProxy(optJsonProxyPort); -+ prx.run(); -+ } else { -+ var dbg = new Debugger(); -+ var web = new DebugWebServer(); -+ dbg.web = web; -+ web.dbg = dbg; -+ dbg.run(); -+ web.run(); -+ } -+} -+ -+main(); -diff --git a/dist/source/debugger/duk_debug_meta.json b/dist/source/debugger/duk_debug_meta.json -new file mode 100644 -index 0000000..ed6bf40 ---- /dev/null -+++ b/dist/source/debugger/duk_debug_meta.json -@@ -0,0 +1,2189 @@ -+{ -+ "error_codes": [ -+ "Unknown", -+ "UnsupportedCommand", -+ "TooMany", -+ "NotFound", -+ "ApplicationError" -+ ], -+ "opcodes": [ -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "LDREG" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "STREG" -+ }, -+ { -+ "args": [ -+ "ABC_JUMP" -+ ], -+ "name": "JUMP" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "LDCONST" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_LDINT" -+ ], -+ "name": "LDINT" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_LDINTX" -+ ], -+ "name": "LDINTX" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "LDTHIS" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "LDUNDEF" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "LDNULL" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "LDTRUE" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "LDFALSE" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "GETVAR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "BNOT" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "LNOT" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "UNM" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "UNP" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "EQ_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "EQ_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "EQ_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "EQ_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "NEQ_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "NEQ_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "NEQ_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "NEQ_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "SEQ_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "SEQ_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "SEQ_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "SEQ_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "SNEQ_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "SNEQ_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "SNEQ_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "SNEQ_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "GT_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "GT_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "GT_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "GT_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "GE_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "GE_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "GE_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "GE_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "LT_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "LT_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "LT_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "LT_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "LE_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "LE_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "LE_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "LE_CC" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "IFTRUE_R" -+ }, -+ { -+ "args": [ -+ "BC_C" -+ ], -+ "name": "IFTRUE_C" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "IFFALSE_R" -+ }, -+ { -+ "args": [ -+ "BC_C" -+ ], -+ "name": "IFFALSE_C" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "ADD_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "ADD_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "ADD_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "ADD_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "SUB_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "SUB_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "SUB_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "SUB_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "MUL_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "MUL_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "MUL_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "MUL_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "DIV_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "DIV_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "DIV_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "DIV_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "MOD_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "MOD_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "MOD_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "MOD_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "EXP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "EXP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "EXP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "EXP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "BAND_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "BAND_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "BAND_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "BAND_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "BOR_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "BOR_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "BOR_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "BOR_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "BXOR_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "BXOR_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "BXOR_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "BXOR_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "BASL_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "BASL_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "BASL_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "BASL_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "BLSR_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "BLSR_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "BLSR_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "BLSR_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "BASR_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "BASR_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "BASR_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "BASR_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "INSTOF_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "INSTOF_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "INSTOF_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "INSTOF_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "IN_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "IN_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "IN_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "IN_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "GETPROP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "GETPROP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "GETPROP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "GETPROP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "PUTPROP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "PUTPROP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "PUTPROP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "PUTPROP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "DELPROP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "DELPROP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "DELPROP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "DELPROP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "PREINCR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "PREDECR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "POSTINCR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "POSTDECR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "PREINCV" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "PREDECV" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "POSTINCV" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "POSTDECV" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "PREINCP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "PREINCP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "PREINCP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "PREINCP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "PREDECP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "PREDECP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "PREDECP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "PREDECP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "POSTINCP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "POSTINCP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "POSTINCP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "POSTINCP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "POSTDECP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "POSTDECP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "POSTDECP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "POSTDECP_CC" -+ }, -+ { -+ "args": [ -+ "A_H", -+ "B_R", -+ "C_R" -+ ], -+ "flags": [ -+ { -+ "mask": 256, -+ "name": "writable" -+ }, -+ { -+ "mask": 512, -+ "name": "enumerable" -+ }, -+ { -+ "mask": 1024, -+ "name": "configurable" -+ }, -+ { -+ "mask": 2048, -+ "name": "accessor" -+ }, -+ { -+ "mask": 4096, -+ "name": "func_decl" -+ } -+ ], -+ "name": "DECLVAR_RR" -+ }, -+ { -+ "args": [ -+ "A_H", -+ "B_C", -+ "C_R" -+ ], -+ "flags": [ -+ { -+ "mask": 256, -+ "name": "writable" -+ }, -+ { -+ "mask": 512, -+ "name": "enumerable" -+ }, -+ { -+ "mask": 1024, -+ "name": "configurable" -+ }, -+ { -+ "mask": 2048, -+ "name": "accessor" -+ }, -+ { -+ "mask": 4096, -+ "name": "func_decl" -+ } -+ ], -+ "name": "DECLVAR_CR" -+ }, -+ { -+ "args": [ -+ "A_H", -+ "B_R", -+ "C_C" -+ ], -+ "flags": [ -+ { -+ "mask": 256, -+ "name": "writable" -+ }, -+ { -+ "mask": 512, -+ "name": "enumerable" -+ }, -+ { -+ "mask": 1024, -+ "name": "configurable" -+ }, -+ { -+ "mask": 2048, -+ "name": "accessor" -+ }, -+ { -+ "mask": 4096, -+ "name": "func_decl" -+ } -+ ], -+ "name": "DECLVAR_RC" -+ }, -+ { -+ "args": [ -+ "A_H", -+ "B_C", -+ "C_C" -+ ], -+ "flags": [ -+ { -+ "mask": 256, -+ "name": "writable" -+ }, -+ { -+ "mask": 512, -+ "name": "enumerable" -+ }, -+ { -+ "mask": 1024, -+ "name": "configurable" -+ }, -+ { -+ "mask": 2048, -+ "name": "accessor" -+ }, -+ { -+ "mask": 4096, -+ "name": "func_decl" -+ } -+ ], -+ "name": "DECLVAR_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "REGEXP_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "REGEXP_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "REGEXP_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "REGEXP_CC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_I" -+ ], -+ "name": "CLOSURE" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "TYPEOF" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "TYPEOFID" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "PUTVAR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_C" -+ ], -+ "name": "DELVAR" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "RETREG" -+ }, -+ { -+ "name": "RETUNDEF" -+ }, -+ { -+ "args": [ -+ "BC_C" -+ ], -+ "name": "RETCONST" -+ }, -+ { -+ "args": [ -+ "BC_C" -+ ], -+ "name": "RETCONSTN" -+ }, -+ { -+ "args": [ -+ "BC_I" -+ ], -+ "name": "LABEL" -+ }, -+ { -+ "args": [ -+ "BC_I" -+ ], -+ "name": "ENDLABEL" -+ }, -+ { -+ "args": [ -+ "BC_I" -+ ], -+ "name": "BREAK" -+ }, -+ { -+ "args": [ -+ "BC_I" -+ ], -+ "name": "CONTINUE" -+ }, -+ { -+ "args": [ -+ "A_H", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 256, -+ "name": "have_catch" -+ }, -+ { -+ "mask": 512, -+ "name": "have_finally" -+ }, -+ { -+ "mask": 1024, -+ "name": "catch_binding" -+ }, -+ { -+ "mask": 2048, -+ "name": "with_binding" -+ } -+ ], -+ "name": "TRYCATCH" -+ }, -+ { -+ "name": "ENDTRY" -+ }, -+ { -+ "name": "ENDCATCH" -+ }, -+ { -+ "args": [ -+ "ABC_R" -+ ], -+ "name": "ENDFIN" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "THROW" -+ }, -+ { -+ "name": "INVLHS" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "CSREG" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R" -+ ], -+ "name": "CSVAR_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C" -+ ], -+ "name": "CSVAR_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R" -+ ], -+ "name": "CSVAR_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C" -+ ], -+ "name": "CSVAR_CC" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL0" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL1" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL2" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL3" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL4" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL5" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL6" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL7" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL8" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL9" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL10" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL11" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL12" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL13" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL14" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "flags": [ -+ { -+ "mask": 1, -+ "name": "tailcall" -+ }, -+ { -+ "mask": 2, -+ "name": "construct" -+ }, -+ { -+ "mask": 4, -+ "name": "called_as_eval" -+ }, -+ { -+ "mask": 8, -+ "name": "indirect" -+ } -+ ], -+ "name": "CALL15" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "name": "NEWOBJ" -+ }, -+ { -+ "args": [ -+ "A_I", -+ "BC_R" -+ ], -+ "name": "NEWARR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_I" -+ ], -+ "name": "MPUTOBJ" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_RI", -+ "C_I" -+ ], -+ "name": "MPUTOBJI" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "INITSET" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "BC_R" -+ ], -+ "name": "INITGET" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_I" -+ ], -+ "name": "MPUTARR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_RI", -+ "C_I" -+ ], -+ "name": "MPUTARRI" -+ }, -+ { -+ "args": [ -+ "B_R", -+ "C_R" -+ ], -+ "name": "SETALEN" -+ }, -+ { -+ "args": [ -+ "B_R", -+ "C_R" -+ ], -+ "name": "INITENUM" -+ }, -+ { -+ "args": [ -+ "B_R", -+ "C_R" -+ ], -+ "name": "NEXTENUM" -+ }, -+ { -+ "args": [ -+ "BC_R" -+ ], -+ "name": "NEWTARGET" -+ }, -+ { -+ "name": "DEBUGGER" -+ }, -+ { -+ "args": [ -+ "ABC_I" -+ ], -+ "name": "NOP" -+ }, -+ { -+ "args": [ -+ "ABC_I" -+ ], -+ "name": "INVALID" -+ }, -+ { -+ "name": "UNUSED207" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_R" -+ ], -+ "name": "GETPROPC_RR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_R" -+ ], -+ "name": "GETPROPC_CR" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_R", -+ "C_C" -+ ], -+ "name": "GETPROPC_RC" -+ }, -+ { -+ "args": [ -+ "A_R", -+ "B_C", -+ "C_C" -+ ], -+ "name": "GETPROPC_CC" -+ }, -+ { -+ "name": "UNUSED212" -+ }, -+ { -+ "name": "UNUSED213" -+ }, -+ { -+ "name": "UNUSED214" -+ }, -+ { -+ "name": "UNUSED215" -+ }, -+ { -+ "name": "UNUSED216" -+ }, -+ { -+ "name": "UNUSED217" -+ }, -+ { -+ "name": "UNUSED218" -+ }, -+ { -+ "name": "UNUSED219" -+ }, -+ { -+ "name": "UNUSED220" -+ }, -+ { -+ "name": "UNUSED221" -+ }, -+ { -+ "name": "UNUSED222" -+ }, -+ { -+ "name": "UNUSED223" -+ }, -+ { -+ "name": "UNUSED224" -+ }, -+ { -+ "name": "UNUSED225" -+ }, -+ { -+ "name": "UNUSED226" -+ }, -+ { -+ "name": "UNUSED227" -+ }, -+ { -+ "name": "UNUSED228" -+ }, -+ { -+ "name": "UNUSED229" -+ }, -+ { -+ "name": "UNUSED230" -+ }, -+ { -+ "name": "UNUSED231" -+ }, -+ { -+ "name": "UNUSED232" -+ }, -+ { -+ "name": "UNUSED233" -+ }, -+ { -+ "name": "UNUSED234" -+ }, -+ { -+ "name": "UNUSED235" -+ }, -+ { -+ "name": "UNUSED236" -+ }, -+ { -+ "name": "UNUSED237" -+ }, -+ { -+ "name": "UNUSED238" -+ }, -+ { -+ "name": "UNUSED239" -+ }, -+ { -+ "name": "UNUSED240" -+ }, -+ { -+ "name": "UNUSED241" -+ }, -+ { -+ "name": "UNUSED242" -+ }, -+ { -+ "name": "UNUSED243" -+ }, -+ { -+ "name": "UNUSED244" -+ }, -+ { -+ "name": "UNUSED245" -+ }, -+ { -+ "name": "UNUSED246" -+ }, -+ { -+ "name": "UNUSED247" -+ }, -+ { -+ "name": "UNUSED248" -+ }, -+ { -+ "name": "UNUSED249" -+ }, -+ { -+ "name": "UNUSED250" -+ }, -+ { -+ "name": "UNUSED251" -+ }, -+ { -+ "name": "UNUSED252" -+ }, -+ { -+ "name": "UNUSED253" -+ }, -+ { -+ "name": "UNUSED254" -+ }, -+ { -+ "name": "UNUSED255" -+ } -+ ], -+ "client_commands": [ -+ "Reserved_0", -+ "Status", -+ "Reserved_2", -+ "Reserved_3", -+ "Reserved_4", -+ "Throw", -+ "Detaching", -+ "AppNotify" -+ ], -+ "class_names": [ -+ "none", -+ "Object", -+ "Array", -+ "Function", -+ "Arguments", -+ "Boolean", -+ "Date", -+ "Error", -+ "JSON", -+ "Math", -+ "Number", -+ "RegExp", -+ "String", -+ "global", -+ "Symbol", -+ "ObjEnv", -+ "DecEnv", -+ "Pointer", -+ "Thread", -+ "ArrayBuffer", -+ "DataView", -+ "Int8Array", -+ "Uint8Array", -+ "Uint8ClampedArray", -+ "Int16Array", -+ "Uint16Array", -+ "Int32Array", -+ "Uint32Array", -+ "Float32Array", -+ "Float64Array" -+ ], -+ "target_commands": [ -+ "Reserved_0", -+ "Reserved_1", -+ "Reserved_2", -+ "Reserved_3", -+ "Reserved_4", -+ "Reserved_5", -+ "Reserved_6", -+ "Reserved_7", -+ "Reserved_8", -+ "Reserved_9", -+ "Reserved_10", -+ "Reserved_11", -+ "Reserved_12", -+ "Reserved_13", -+ "Reserved_14", -+ "Reserved_15", -+ "BasicInfo", -+ "TriggerStatus", -+ "Pause", -+ "Resume", -+ "StepInto", -+ "StepOver", -+ "StepOut", -+ "ListBreak", -+ "AddBreak", -+ "DelBreak", -+ "GetVar", -+ "PutVar", -+ "GetCallStack", -+ "GetLocals", -+ "Eval", -+ "Detach", -+ "DumpHeap", -+ "GetBytecode", -+ "AppRequest", -+ "GetHeapObjInfo", -+ "GetObjPropDesc", -+ "GetObjPropDescRange" -+ ] -+} -diff --git a/dist/source/debugger/duk_debug_proxy.js b/dist/source/debugger/duk_debug_proxy.js -new file mode 100644 -index 0000000..fd8ba91 ---- /dev/null -+++ b/dist/source/debugger/duk_debug_proxy.js -@@ -0,0 +1,1044 @@ -+/* -+ * JSON debug proxy written in DukLuv -+ * -+ * This single file JSON debug proxy implementation is an alternative to the -+ * Node.js-based proxy in duk_debug.js. DukLuv is a much smaller dependency -+ * than Node.js so embedding DukLuv in a debug client is easier. -+ */ -+ -+'use strict'; -+ -+// XXX: Code assumes uv.write() will write fully. This is not necessarily -+// true; should add support for partial writes (or at least failing when -+// a partial write occurs). -+ -+var log = new Duktape.Logger('Proxy'); // default logger -+//log.l = 0; // enable debug and trace logging -+ -+/* -+ * Config -+ */ -+ -+var serverHost = '0.0.0.0'; -+var serverPort = 9093; -+var targetHost = '127.0.0.1'; -+var targetPort = 9091; -+var singleConnection = false; -+var readableNumberValue = false; -+var lenientJsonParse = false; -+var jxParse = false; -+var metadataFile = null; -+var metadata = {}; -+var TORTURE = false; // for manual testing of binary/json parsing robustness -+ -+/* -+ * Duktape 1.x and 2.x buffer harmonization -+ */ -+ -+var allocPlain = (typeof Uint8Array.allocPlain === 'function' ? -+ Uint8Array.allocPlain : Duktape.Buffer); -+var plainOf = (typeof Uint8Array.plainOf === 'function' ? -+ Uint8Array.plainOf : Duktape.Buffer); -+var bufferToString = (typeof String.fromBuffer === 'function' ? -+ String.fromBuffer : String); -+ -+/* -+ * Detect missing 'var' declarations -+ */ -+ -+// Prevent new bindings on global object. This detects missing 'var' -+// declarations, e.g. "x = 123;" in a function without declaring it. -+var global = new Function('return this;')(); -+log.debug('Preventing extensions on global object'); -+log.debug('Global is extensible:', Object.isExtensible(global)); -+Object.preventExtensions(global); -+log.debug('Global is extensible:', Object.isExtensible(global)); -+ -+/* -+ * Misc helpers -+ */ -+ -+function jxEncode(v) { -+ return Duktape.enc('jx', v); -+} -+ -+function plainBufferCopy(typedarray) { -+ // This is still pretty awkward in Duktape 1.4.x. -+ // Argument may be a "slice" and we want a copy of the slice -+ // (not the full underlying buffer). -+ -+ var u8 = new Uint8Array(typedarray.length); -+ u8.set(typedarray); // make a copy, ensuring there's no slice offset -+ return plainOf(u8); // get underlying plain buffer -+} -+ -+function isObject(x) { -+ // Note that typeof null === 'object'. -+ return (typeof x === 'object' && x !== null); -+} -+ -+function readFully(filename, cb) { -+ uv.fs_open(metadataFile, 'r', 0, function (handle, err) { -+ var fileOff = 0; -+ var data = new Uint8Array(256); -+ var dataOff = 0; -+ -+ if (err) { -+ return cb(null, err); -+ } -+ function readCb(buf, err) { -+ var res; -+ var newData; -+ -+ log.debug('Read callback:', buf.length, err); -+ if (err) { -+ uv.fs_close(handle); -+ return cb(null, err); -+ } -+ if (buf.length == 0) { -+ uv.fs_close(handle); -+ res = new Uint8Array(dataOff); -+ res.set(data.subarray(0, dataOff)); -+ res = plainOf(res); // plain buffer -+ log.debug('Read', res.length, 'bytes from', filename); -+ return cb(res, null); -+ } -+ while (data.length - dataOff < buf.length) { -+ log.debug('Resize file read buffer:', data.length, '->', data.length * 2); -+ newData = new Uint8Array(data.length * 2); -+ newData.set(data); -+ data = newData; -+ } -+ data.set(new Uint8Array(buf), dataOff); -+ dataOff += buf.length; -+ fileOff += buf.length; -+ uv.fs_read(handle, 4096, fileOff, readCb); -+ } -+ uv.fs_read(handle, 4096, fileOff, readCb); -+ }); -+} -+ -+/* -+ * JSON proxy server -+ * -+ * Accepts an incoming JSON proxy client and connects to a debug target, -+ * tying the two connections together. Supports both a single connection -+ * and a persistent mode. -+ */ -+ -+function JsonProxyServer(host, port) { -+ this.name = 'JsonProxyServer'; -+ this.handle = uv.new_tcp(); -+ uv.tcp_bind(this.handle, host, port); -+ uv.listen(this.handle, 128, this.onConnection.bind(this)); -+} -+ -+JsonProxyServer.prototype.onConnection = function onConnection(err) { -+ if (err) { -+ log.error('JSON proxy onConnection error:', err); -+ return; -+ } -+ log.info('JSON proxy client connected'); // XXX: it'd be nice to log remote peer host:port -+ -+ var jsonSock = new JsonConnHandler(this); -+ var targSock = new TargetConnHandler(this); -+ jsonSock.targetHandler = targSock; -+ targSock.jsonHandler = jsonSock; -+ uv.accept(this.handle, jsonSock.handle); -+ -+ log.info('Connecting to debug target at', targetHost + ':' + targetPort); -+ jsonSock.writeJson({ notify: '_TargetConnecting', args: [ targetHost, targetPort ] }); -+ uv.tcp_connect(targSock.handle, targetHost, targetPort, targSock.onConnect.bind(targSock)); -+ -+ if (singleConnection) { -+ log.info('Single connection mode, stop listening for more connections'); -+ uv.shutdown(this.handle); -+ uv.read_stop(this.handle); // unnecessary but just in case -+ uv.close(this.handle); -+ this.handle = null; -+ } -+}; -+ -+JsonProxyServer.prototype.onProxyClientDisconnected = function onProxyClientDisconnected() { -+ // When this is invoked the proxy connection and the target connection -+ // have both been closed. -+ if (singleConnection) { -+ log.info('Proxy connection finished (single connection mode: we should be exiting now)'); -+ } else { -+ log.info('Proxy connection finished (persistent mode: wait for more connections)'); -+ } -+}; -+ -+/* -+ * JSON connection handler -+ */ -+ -+function JsonConnHandler(server) { -+ var i, n; -+ -+ this.name = 'JsonConnHandler'; -+ this.server = server; -+ this.handle = uv.new_tcp(); -+ this.incoming = new Uint8Array(4096); -+ this.incomingOffset = 0; -+ this.targetHandler = null; -+ -+ this.commandNumberLookup = {}; -+ if (metadata && metadata.target_commands) { -+ for (i = 0, n = metadata.target_commands.length; i < n; i++) { -+ this.commandNumberLookup[metadata.target_commands[i]] = i; -+ } -+ } -+} -+ -+JsonConnHandler.prototype.finish = function finish(msg) { -+ var args; -+ -+ if (!this.handle) { -+ log.info('JsonConnHandler already disconnected, ignore finish()'); -+ return; -+ } -+ log.info('JsonConnHandler finished:', msg); -+ try { -+ args = msg ? [ msg ] : void 0; -+ this.writeJson({ notify: '_Disconnecting', args: args }); -+ } catch (e) { -+ log.info('Failed to write _Disconnecting notify, ignoring:', e); -+ } -+ uv.shutdown(this.handle); -+ uv.read_stop(this.handle); -+ uv.close(this.handle); -+ this.handle = null; -+ -+ this.targetHandler.finish(msg); // disconnect target too (if not already disconnected) -+ -+ this.server.onProxyClientDisconnected(); -+}; -+ -+JsonConnHandler.prototype.onRead = function onRead(err, data) { -+ var newIncoming; -+ var msg; -+ var errmsg; -+ var tmpBuf; -+ -+ log.trace('Received data from JSON socket, err:', err, 'data length:', data ? data.length : 'null'); -+ -+ if (err) { -+ errmsg = 'Error reading data from JSON debug client: ' + err; -+ this.finish(errmsg); -+ return; -+ } -+ if (data) { -+ // Feed the data one byte at a time when torture testing. -+ if (TORTURE && data.length > 1) { -+ for (var i = 0; i < data.length; i++) { -+ tmpBuf = allocPlain(1); -+ tmpBuf[0] = data[i]; -+ this.onRead(null, tmpBuf); -+ } -+ return; -+ } -+ -+ // Receive data into 'incoming', resizing as necessary. -+ while (data.length > this.incoming.length - this.incomingOffset) { -+ newIncoming = new Uint8Array(this.incoming.length * 1.3 + 16); -+ newIncoming.set(this.incoming); -+ this.incoming = newIncoming; -+ log.debug('Resize incoming JSON buffer to ' + this.incoming.length); -+ } -+ this.incoming.set(new Uint8Array(data), this.incomingOffset); -+ this.incomingOffset += data.length; -+ -+ // Trial parse JSON message(s). -+ while (true) { -+ msg = this.trialParseJsonMessage(); -+ if (!msg) { -+ break; -+ } -+ try { -+ this.dispatchJsonMessage(msg); -+ } catch (e) { -+ errmsg = 'JSON message dispatch failed: ' + e; -+ this.writeJson({ notify: '_Error', args: [ errmsg ] }); -+ if (lenientJsonParse) { -+ log.warn('JSON message dispatch failed (lenient mode, ignoring):', e); -+ } else { -+ log.warn('JSON message dispatch failed (dropping connection):', e); -+ this.finish(errmsg); -+ } -+ } -+ } -+ } else { -+ this.finish('JSON proxy client disconnected'); -+ } -+}; -+ -+JsonConnHandler.prototype.writeJson = function writeJson(msg) { -+ log.info('PROXY --> CLIENT:', JSON.stringify(msg)); -+ if (this.handle) { -+ uv.write(this.handle, JSON.stringify(msg) + '\n'); -+ } -+}; -+ -+JsonConnHandler.prototype.handleDebugMessage = function handleDebugMessage(dvalues) { -+ var msg = {}; -+ var idx = 0; -+ var cmd; -+ -+ if (dvalues.length <= 0) { -+ throw new Error('invalid dvalues list: length <= 0'); -+ } -+ var x = dvalues[idx++]; -+ if (!isObject(x)) { -+ throw new Error('invalid initial dvalue: ' + Duktape.enc('jx', dvalues)); -+ } -+ if (x.type === 'req') { -+ cmd = dvalues[idx++]; -+ if (typeof cmd !== 'number') { -+ throw new Error('invalid command: ' + Duktape.enc('jx', cmd)); -+ } -+ msg.request = this.determineCommandName(cmd) || true; -+ msg.command = cmd; -+ } else if (x.type === 'rep') { -+ msg.reply = true; -+ } else if (x.type === 'err') { -+ msg.error = true; -+ } else if (x.type === 'nfy') { -+ cmd = dvalues[idx++]; -+ if (typeof cmd !== 'number') { -+ throw new Error('invalid command: ' + Duktape.enc('jx', cmd)); -+ } -+ msg.notify = this.determineCommandName(cmd) || true; -+ msg.command = cmd; -+ } else { -+ throw new Error('invalid initial dvalue: ' + Duktape.enc('jx', dvalues)); -+ } -+ -+ for (; idx < dvalues.length - 1; idx++) { -+ if (!msg.args) { -+ msg.args = []; -+ } -+ msg.args.push(dvalues[idx]); -+ } -+ -+ if (!isObject(dvalues[idx]) || dvalues[idx].type !== 'eom') { -+ throw new Error('invalid final dvalue: ' + Duktape.enc('jx', dvalues)); -+ } -+ -+ this.writeJson(msg); -+}; -+ -+JsonConnHandler.prototype.determineCommandName = function determineCommandName(cmd) { -+ if (!(metadata && metadata.client_commands)) { -+ return; -+ } -+ return metadata.client_commands[cmd]; -+}; -+ -+JsonConnHandler.prototype.trialParseJsonMessage = function trialParseJsonMessage() { -+ var buf = this.incoming; -+ var avail = this.incomingOffset; -+ var i; -+ var msg, str, errmsg; -+ -+ for (i = 0; i < avail; i++) { -+ if (buf[i] == 0x0a) { -+ str = bufferToString(plainBufferCopy(buf.subarray(0, i))); -+ try { -+ if (jxParse) { -+ msg = Duktape.dec('jx', str); -+ } else { -+ msg = JSON.parse(str); -+ } -+ } catch (e) { -+ // In lenient mode if JSON parse fails just send back an _Error -+ // and ignore the line (useful for initial development). -+ // -+ // In non-lenient mode drop the connection here; if the failed line -+ // was a request the client is expecting a reply/error message back -+ // (otherwise it may go out of sync) but we can't send a synthetic -+ // one (as we can't parse the request). -+ errmsg = 'JSON parse failed for: ' + jxEncode(str) + ': ' + e; -+ this.writeJson({ notify: '_Error', args: [ errmsg ] }); -+ if (lenientJsonParse) { -+ log.warn('JSON parse failed (lenient mode, ignoring):', e); -+ } else { -+ log.warn('JSON parse failed (dropping connection):', e); -+ this.finish(errmsg); -+ } -+ } -+ -+ this.incoming.set(this.incoming.subarray(i + 1)); -+ this.incomingOffset -= i + 1; -+ return msg; -+ } -+ } -+}; -+ -+JsonConnHandler.prototype.dispatchJsonMessage = function dispatchJsonMessage(msg) { -+ var cmd; -+ var dvalues = []; -+ var i, n; -+ -+ log.info('PROXY <-- CLIENT:', JSON.stringify(msg)); -+ -+ // Parse message type, determine initial marker for binary message. -+ if (msg.request) { -+ cmd = this.determineCommandNumber(msg.request, msg.command); -+ dvalues.push(new Uint8Array([ 0x01 ])); -+ dvalues.push(this.encodeJsonDvalue(cmd)); -+ } else if (msg.reply) { -+ dvalues.push(new Uint8Array([ 0x02 ])); -+ } else if (msg.notify) { -+ cmd = this.determineCommandNumber(msg.notify, msg.command); -+ dvalues.push(new Uint8Array([ 0x04 ])); -+ dvalues.push(this.encodeJsonDvalue(cmd)); -+ } else if (msg.error) { -+ dvalues.push(new Uint8Array([ 0x03 ])); -+ } else { -+ throw new Error('invalid input JSON message: ' + jxEncode(msg)); -+ } -+ -+ // Encode arguments into dvalues. -+ for (i = 0, n = (msg.args ? msg.args.length : 0); i < n; i++) { -+ dvalues.push(this.encodeJsonDvalue(msg.args[i])); -+ } -+ -+ // Add an EOM, and write out the dvalues to the debug target. -+ dvalues.push(new Uint8Array([ 0x00 ])); -+ for (i = 0, n = dvalues.length; i < n; i++) { -+ this.targetHandler.writeBinary(dvalues[i]); -+ } -+}; -+ -+JsonConnHandler.prototype.determineCommandNumber = function determineCommandNumber(name, val) { -+ var res; -+ -+ if (typeof name === 'string') { -+ res = this.commandNumberLookup[name]; -+ if (!res) { -+ log.info('Unknown command name: ' + name + ', command number: ' + val); -+ } -+ } else if (typeof name === 'number') { -+ res = name; -+ } else if (name !== true) { -+ throw new Error('invalid command name (must be string, number, or "true"): ' + name); -+ } -+ if (typeof res === 'undefined' && typeof val === 'undefined') { -+ throw new Error('cannot determine command number from name: ' + name); -+ } -+ if (typeof val !== 'number' && typeof val !== 'undefined') { -+ throw new Error('invalid command number: ' + val); -+ } -+ res = res || val; -+ return res; -+}; -+ -+JsonConnHandler.prototype.writeDebugStringToBuffer = function writeDebugStringToBuffer(v, buf, off) { -+ var i, n; -+ -+ for (i = 0, n = v.length; i < n; i++) { -+ buf[off + i] = v.charCodeAt(i) & 0xff; // truncate higher bits -+ } -+}; -+ -+JsonConnHandler.prototype.encodeJsonDvalue = function encodeJsonDvalue(v) { -+ var buf, dec, len, dv; -+ -+ if (isObject(v)) { -+ if (v.type === 'eom') { -+ return new Uint8Array([ 0x00 ]); -+ } else if (v.type === 'req') { -+ return new Uint8Array([ 0x01 ]); -+ } else if (v.type === 'rep') { -+ return new Uint8Array([ 0x02 ]); -+ } else if (v.type === 'err') { -+ return new Uint8Array([ 0x03 ]); -+ } else if (v.type === 'nfy') { -+ return new Uint8Array([ 0x04 ]); -+ } else if (v.type === 'unused') { -+ return new Uint8Array([ 0x15 ]); -+ } else if (v.type === 'undefined') { -+ return new Uint8Array([ 0x16 ]); -+ } else if (v.type === 'number') { -+ dec = Duktape.dec('hex', v.data); -+ len = dec.length; -+ if (len !== 8) { -+ throw new TypeError('value cannot be converted to dvalue: ' + jxEncode(v)); -+ } -+ buf = new Uint8Array(1 + len); -+ buf[0] = 0x1a; -+ buf.set(new Uint8Array(dec), 1); -+ return buf; -+ } else if (v.type === 'buffer') { -+ dec = Duktape.dec('hex', v.data); -+ len = dec.length; -+ if (len <= 0xffff) { -+ buf = new Uint8Array(3 + len); -+ buf[0] = 0x14; -+ buf[1] = (len >> 8) & 0xff; -+ buf[2] = (len >> 0) & 0xff; -+ buf.set(new Uint8Arrau(dec), 3); -+ return buf; -+ } else { -+ buf = new Uint8Array(5 + len); -+ buf[0] = 0x13; -+ buf[1] = (len >> 24) & 0xff; -+ buf[2] = (len >> 16) & 0xff; -+ buf[3] = (len >> 8) & 0xff; -+ buf[4] = (len >> 0) & 0xff; -+ buf.set(new Uint8Array(dec), 5); -+ return buf; -+ } -+ } else if (v.type === 'object') { -+ dec = Duktape.dec('hex', v.pointer); -+ len = dec.length; -+ buf = new Uint8Array(3 + len); -+ buf[0] = 0x1b; -+ buf[1] = v.class; -+ buf[2] = len; -+ buf.set(new Uint8Array(dec), 3); -+ return buf; -+ } else if (v.type === 'pointer') { -+ dec = Duktape.dec('hex', v.pointer); -+ len = dec.length; -+ buf = new Uint8Array(2 + len); -+ buf[0] = 0x1c; -+ buf[1] = len; -+ buf.set(new Uint8Array(dec), 2); -+ return buf; -+ } else if (v.type === 'lightfunc') { -+ dec = Duktape.dec('hex', v.pointer); -+ len = dec.length; -+ buf = new Uint8Array(4 + len); -+ buf[0] = 0x1d; -+ buf[1] = (v.flags >> 8) & 0xff; -+ buf[2] = v.flags & 0xff; -+ buf[3] = len; -+ buf.set(new Uint8Array(dec), 4); -+ return buf; -+ } else if (v.type === 'heapptr') { -+ dec = Duktape.dec('hex', v.pointer); -+ len = dec.length; -+ buf = new Uint8Array(2 + len); -+ buf[0] = 0x1e; -+ buf[1] = len; -+ buf.set(new Uint8Array(dec), 2); -+ return buf; -+ } -+ } else if (v === null) { -+ return new Uint8Array([ 0x17 ]); -+ } else if (typeof v === 'boolean') { -+ return new Uint8Array([ v ? 0x18 : 0x19 ]); -+ } else if (typeof v === 'number') { -+ if (Math.floor(v) === v && /* whole */ -+ (v !== 0 || 1 / v > 0) && /* not negative zero */ -+ v >= -0x80000000 && v <= 0x7fffffff) { -+ // Represented signed 32-bit integers as plain integers. -+ // Debugger code expects this for all fields that are not -+ // duk_tval representations (e.g. command numbers and such). -+ if (v >= 0x00 && v <= 0x3f) { -+ return new Uint8Array([ 0x80 + v ]); -+ } else if (v >= 0x0000 && v <= 0x3fff) { -+ return new Uint8Array([ 0xc0 + (v >> 8), v & 0xff ]); -+ } else if (v >= -0x80000000 && v <= 0x7fffffff) { -+ return new Uint8Array([ 0x10, -+ (v >> 24) & 0xff, -+ (v >> 16) & 0xff, -+ (v >> 8) & 0xff, -+ (v >> 0) & 0xff ]); -+ } else { -+ throw new Error('internal error when encoding integer to dvalue: ' + v); -+ } -+ } else { -+ // Represent non-integers as IEEE double dvalues. -+ buf = new Uint8Array(1 + 8); -+ buf[0] = 0x1a; -+ new DataView(buf).setFloat64(1, v, false); -+ return buf; -+ } -+ } else if (typeof v === 'string') { -+ if (v.length < 0 || v.length > 0xffffffff) { -+ // Not possible in practice. -+ throw new TypeError('cannot convert to dvalue, invalid string length: ' + v.length); -+ } -+ if (v.length <= 0x1f) { -+ buf = new Uint8Array(1 + v.length); -+ buf[0] = 0x60 + v.length; -+ this.writeDebugStringToBuffer(v, buf, 1); -+ return buf; -+ } else if (v.length <= 0xffff) { -+ buf = new Uint8Array(3 + v.length); -+ buf[0] = 0x12; -+ buf[1] = (v.length >> 8) & 0xff; -+ buf[2] = (v.length >> 0) & 0xff; -+ this.writeDebugStringToBuffer(v, buf, 3); -+ return buf; -+ } else { -+ buf = new Uint8Array(5 + v.length); -+ buf[0] = 0x11; -+ buf[1] = (v.length >> 24) & 0xff; -+ buf[2] = (v.length >> 16) & 0xff; -+ buf[3] = (v.length >> 8) & 0xff; -+ buf[4] = (v.length >> 0) & 0xff; -+ this.writeDebugStringToBuffer(v, buf, 5); -+ return buf; -+ } -+ } -+ -+ throw new TypeError('value cannot be converted to dvalue: ' + jxEncode(v)); -+}; -+ -+/* -+ * Target binary connection handler -+ */ -+ -+function TargetConnHandler(server) { -+ this.name = 'TargetConnHandler'; -+ this.server = server; -+ this.handle = uv.new_tcp(); -+ this.jsonHandler = null; -+ this.incoming = new Uint8Array(4096); -+ this.incomingOffset = 0; -+ this.dvalues = []; -+} -+ -+TargetConnHandler.prototype.finish = function finish(msg) { -+ if (!this.handle) { -+ log.info('TargetConnHandler already disconnected, ignore finish()'); -+ return; -+ } -+ log.info('TargetConnHandler finished:', msg); -+ -+ this.jsonHandler.writeJson({ notify: '_TargetDisconnected' }); -+ -+ // XXX: write a notify to target? -+ -+ uv.shutdown(this.handle); -+ uv.read_stop(this.handle); -+ uv.close(this.handle); -+ this.handle = null; -+ -+ this.jsonHandler.finish(msg); // disconnect JSON client too (if not already disconnected) -+}; -+ -+TargetConnHandler.prototype.onConnect = function onConnect(err) { -+ var errmsg; -+ -+ if (err) { -+ errmsg = 'Failed to connect to target: ' + err; -+ log.warn(errmsg); -+ this.jsonHandler.writeJson({ notify: '_Error', args: [ String(err) ] }); -+ this.finish(errmsg); -+ return; -+ } -+ -+ // Once we're connected to the target, start read both binary and JSON -+ // input. We don't want to read JSON input before this so that we can -+ // always translate incoming messages to dvalues and write them out -+ // without queueing. Any pending JSON messages will be queued by the -+ // OS instead. -+ -+ log.info('Connected to debug target at', targetHost + ':' + targetPort); -+ uv.read_start(this.jsonHandler.handle, this.jsonHandler.onRead.bind(this.jsonHandler)); -+ uv.read_start(this.handle, this.onRead.bind(this)); -+}; -+ -+TargetConnHandler.prototype.writeBinary = function writeBinary(buf) { -+ var plain = plainBufferCopy(buf); -+ log.info('PROXY --> TARGET:', Duktape.enc('jx', plain)); -+ if (this.handle) { -+ uv.write(this.handle, plain); -+ } -+}; -+ -+TargetConnHandler.prototype.onRead = function onRead(err, data) { -+ var res; -+ var errmsg; -+ var tmpBuf; -+ var newIncoming; -+ -+ log.trace('Received data from target socket, err:', err, 'data length:', data ? data.length : 'null'); -+ -+ if (err) { -+ errmsg = 'Error reading data from debug target: ' + err; -+ this.finish(errmsg); -+ return; -+ } -+ -+ if (data) { -+ // Feed the data one byte at a time when torture testing. -+ if (TORTURE && data.length > 1) { -+ for (var i = 0; i < data.length; i++) { -+ tmpBuf = allocPlain(1); -+ tmpBuf[0] = data[i]; -+ this.onRead(null, tmpBuf); -+ } -+ return; -+ } -+ -+ // Receive data into 'incoming', resizing as necessary. -+ while (data.length > this.incoming.length - this.incomingOffset) { -+ newIncoming = new Uint8Array(this.incoming.length * 1.3 + 16); -+ newIncoming.set(this.incoming); -+ this.incoming = newIncoming; -+ log.debug('Resize incoming binary buffer to ' + this.incoming.length); -+ } -+ this.incoming.set(new Uint8Array(data), this.incomingOffset); -+ this.incomingOffset += data.length; -+ -+ // Trial parse handshake unless done. -+ if (!this.handshake) { -+ this.trialParseHandshake(); -+ } -+ -+ // Trial parse dvalue(s) and debug messages. -+ if (this.handshake) { -+ for (;;) { -+ res = this.trialParseDvalue(); -+ if (!res) { -+ break; -+ } -+ log.trace('Got dvalue:', Duktape.enc('jx', res.dvalue)); -+ this.dvalues.push(res.dvalue); -+ if (isObject(res.dvalue) && res.dvalue.type === 'eom') { -+ try { -+ this.jsonHandler.handleDebugMessage(this.dvalues); -+ this.dvalues = []; -+ } catch (e) { -+ errmsg = 'JSON message handling failed: ' + e; -+ this.jsonHandler.writeJson({ notify: '_Error', args: [ errmsg ] }); -+ if (lenientJsonParse) { -+ log.warn('JSON message handling failed (lenient mode, ignoring):', e); -+ } else { -+ log.warn('JSON message handling failed (dropping connection):', e); -+ this.finish(errmsg); -+ } -+ } -+ } -+ } -+ } -+ } else { -+ log.info('Target disconnected'); -+ this.finish('Target disconnected'); -+ } -+}; -+ -+TargetConnHandler.prototype.trialParseHandshake = function trialParseHandshake() { -+ var buf = this.incoming; -+ var avail = this.incomingOffset; -+ var i; -+ var msg; -+ var m; -+ var protocolVersion; -+ -+ for (i = 0; i < avail; i++) { -+ if (buf[i] == 0x0a) { -+ msg = bufferToString(plainBufferCopy(buf.subarray(0, i))); -+ this.incoming.set(this.incoming.subarray(i + 1)); -+ this.incomingOffset -= i + 1; -+ -+ // Generic handshake format: only relies on initial version field. -+ m = /^(\d+) (.*)$/.exec(msg) || {}; -+ protocolVersion = +m[1]; -+ this.handshake = { -+ line: msg, -+ protocolVersion: protocolVersion, -+ text: m[2] -+ }; -+ -+ // More detailed v1 handshake line. -+ if (protocolVersion === 1) { -+ m = /^(\d+) (\d+) (.*?) (.*?) (.*)$/.exec(msg) || {}; -+ this.handshake.dukVersion = m[1]; -+ this.handshake.dukGitDescribe = m[2]; -+ this.handshake.targetString = m[3]; -+ } -+ -+ this.jsonHandler.writeJson({ notify: '_TargetConnected', args: [ msg ] }); -+ -+ log.info('Target handshake: ' + JSON.stringify(this.handshake)); -+ return; -+ } -+ } -+}; -+ -+TargetConnHandler.prototype.bufferToDebugString = function bufferToDebugString(buf) { -+ return String.fromCharCode.apply(null, buf); -+}; -+ -+TargetConnHandler.prototype.trialParseDvalue = function trialParseDvalue() { -+ var _this = this; -+ var buf = this.incoming; -+ var avail = this.incomingOffset; -+ var v; -+ var gotValue = false; // explicit flag for e.g. v === undefined -+ var dv = new DataView(buf); -+ var tmp; -+ var x; -+ var len; -+ -+ function consume(n) { -+ log.info('PROXY <-- TARGET:', Duktape.enc('jx', _this.incoming.subarray(0, n))); -+ _this.incoming.set(_this.incoming.subarray(n)); -+ _this.incomingOffset -= n; -+ } -+ -+ x = buf[0]; -+ if (avail <= 0) { -+ ; -+ } else if (x >= 0xc0) { -+ // 0xc0...0xff: integers 0-16383 -+ if (avail >= 2) { -+ v = ((x - 0xc0) << 8) + buf[1]; -+ consume(2); -+ } -+ } else if (x >= 0x80) { -+ // 0x80...0xbf: integers 0-63 -+ v = x - 0x80; -+ consume(1); -+ } else if (x >= 0x60) { -+ // 0x60...0x7f: strings with length 0-31 -+ len = x - 0x60; -+ if (avail >= 1 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(1, 1 + len)); -+ v = this.bufferToDebugString(v); -+ consume(1 + len); -+ } -+ } else { -+ switch (x) { -+ case 0x00: consume(1); v = { type: 'eom' }; break; -+ case 0x01: consume(1); v = { type: 'req' }; break; -+ case 0x02: consume(1); v = { type: 'rep' }; break; -+ case 0x03: consume(1); v = { type: 'err' }; break; -+ case 0x04: consume(1); v = { type: 'nfy' }; break; -+ case 0x10: // 4-byte signed integer -+ if (avail >= 5) { -+ v = dv.getInt32(1, false); -+ consume(5); -+ } -+ break; -+ case 0x11: // 4-byte string -+ if (avail >= 5) { -+ len = dv.getUint32(1, false); -+ if (avail >= 5 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(5, 5 + len)); -+ v = this.bufferToDebugString(v); -+ consume(5 + len); -+ } -+ } -+ break; -+ case 0x12: // 2-byte string -+ if (avail >= 3) { -+ len = dv.getUint16(1, false); -+ if (avail >= 3 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(3, 3 + len)); -+ v = this.bufferToDebugString(v); -+ consume(3 + len); -+ } -+ } -+ break; -+ case 0x13: // 4-byte buffer -+ if (avail >= 5) { -+ len = dv.getUint32(1, false); -+ if (avail >= 5 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(5, 5 + len)); -+ v = { type: 'buffer', data: Duktape.enc('hex', plainOf(v)) }; -+ consume(5 + len); -+ } -+ } -+ break; -+ case 0x14: // 2-byte buffer -+ if (avail >= 3) { -+ len = dv.getUint16(1, false); -+ if (avail >= 3 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(3, 3 + len)); -+ v = { type: 'buffer', data: Duktape.enc('hex', plainOf(v)) }; -+ consume(3 + len); -+ } -+ } -+ break; -+ case 0x15: // unused/none -+ v = { type: 'unused' }; -+ consume(1); -+ break; -+ case 0x16: // undefined -+ v = { type: 'undefined' }; -+ gotValue = true; // indicate 'v' is actually set -+ consume(1); -+ break; -+ case 0x17: // null -+ v = null; -+ gotValue = true; // indicate 'v' is actually set -+ consume(1); -+ break; -+ case 0x18: // true -+ v = true; -+ consume(1); -+ break; -+ case 0x19: // false -+ v = false; -+ consume(1); -+ break; -+ case 0x1a: // number (IEEE double), big endian -+ if (avail >= 9) { -+ tmp = new Uint8Array(8); -+ tmp.set(buf.subarray(1, 9)); -+ v = { type: 'number', data: Duktape.enc('hex', plainOf(tmp)) }; -+ if (readableNumberValue) { -+ // The value key should not be used programmatically, -+ // it is just there to make the dumps more readable. -+ v.value = new DataView(tmp.buffer).getFloat64(0, false); -+ } -+ consume(9); -+ } -+ break; -+ case 0x1b: // object -+ if (avail >= 3) { -+ len = buf[2]; -+ if (avail >= 3 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(3, 3 + len)); -+ v = { type: 'object', 'class': buf[1], pointer: Duktape.enc('hex', plainOf(v)) }; -+ consume(3 + len); -+ } -+ } -+ break; -+ case 0x1c: // pointer -+ if (avail >= 2) { -+ len = buf[1]; -+ if (avail >= 2 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(2, 2 + len)); -+ v = { type: 'pointer', pointer: Duktape.enc('hex', plainOf(v)) }; -+ consume(2 + len); -+ } -+ } -+ break; -+ case 0x1d: // lightfunc -+ if (avail >= 4) { -+ len = buf[3]; -+ if (avail >= 4 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(4, 4 + len)); -+ v = { type: 'lightfunc', flags: dv.getUint16(1, false), pointer: Duktape.enc('hex', plainOf(v)) }; -+ consume(4 + len); -+ } -+ } -+ break; -+ case 0x1e: // heapptr -+ if (avail >= 2) { -+ len = buf[1]; -+ if (avail >= 2 + len) { -+ v = new Uint8Array(len); -+ v.set(buf.subarray(2, 2 + len)); -+ v = { type: 'heapptr', pointer: Duktape.enc('hex', plainOf(v)) }; -+ consume(2 + len); -+ } -+ } -+ break; -+ default: -+ throw new Error('failed parse initial byte: ' + buf[0]); -+ } -+ } -+ -+ if (typeof v !== 'undefined' || gotValue) { -+ return { dvalue: v }; -+ } -+}; -+ -+/* -+ * Main -+ */ -+ -+function main() { -+ var argv = typeof uv.argv === 'function' ? uv.argv() : []; -+ var i; -+ for (i = 2; i < argv.length; i++) { // skip dukluv and script name -+ if (argv[i] == '--help') { -+ print('Usage: dukluv ' + argv[1] + ' [option]+'); -+ print(''); -+ print(' --server-host HOST JSON proxy server listen address'); -+ print(' --server-port PORT JSON proxy server listen port'); -+ print(' --target-host HOST Debug target address'); -+ print(' --target-port PORT Debug target port'); -+ print(' --metadata FILE Proxy metadata file (usually named duk_debug_meta.json)'); -+ print(' --log-level LEVEL Set log level, default is 2; 0=trace, 1=debug, 2=info, 3=warn, etc'); -+ print(' --single Run a single proxy connection and exit (default: persist for multiple connections)'); -+ print(' --readable-numbers Add a non-programmatic "value" key for IEEE doubles help readability'); -+ print(' --lenient Ignore (with warning) invalid JSON without dropping connection'); -+ print(' --jx-parse Parse JSON proxy input with JX, useful when testing manually'); -+ print(''); -+ return; // don't register any sockets/timers etc to exit -+ } else if (argv[i] == '--single') { -+ singleConnection = true; -+ continue; -+ } else if (argv[i] == '--readable-numbers') { -+ readableNumberValue = true; -+ continue; -+ } else if (argv[i] == '--lenient') { -+ lenientJsonParse = true; -+ continue; -+ } else if (argv[i] == '--jx-parse') { -+ jxParse = true; -+ continue; -+ } -+ if (i >= argv.length - 1) { -+ throw new Error('missing option value for ' + argv[i]); -+ } -+ if (argv[i] == '--server-host') { -+ serverHost = argv[i + 1]; -+ i++; -+ } else if (argv[i] == '--server-port') { -+ serverPort = Math.floor(+argv[i + 1]); -+ i++; -+ } else if (argv[i] == '--target-host') { -+ targetHost = argv[i + 1]; -+ i++; -+ } else if (argv[i] == '--target-port') { -+ targetPort = Math.floor(+argv[i + 1]); -+ i++; -+ } else if (argv[i] == '--metadata') { -+ metadataFile = argv[i + 1]; -+ i++; -+ } else if (argv[i] == '--log-level') { -+ log.l = Math.floor(+argv[i + 1]); -+ i++; -+ } else { -+ throw new Error('invalid option ' + argv[i]); -+ } -+ } -+ -+ function runServer() { -+ var serverSocket = new JsonProxyServer(serverHost, serverPort); -+ var connMode = singleConnection ? 'single connection mode' : 'persistent connection mode'; -+ log.info('Listening for incoming JSON debug connection on ' + serverHost + ':' + serverPort + -+ ', target is ' + targetHost + ':' + targetPort + ', ' + connMode); -+ } -+ -+ if (metadataFile) { -+ log.info('Read proxy metadata from', metadataFile); -+ readFully(metadataFile, function (data, err) { -+ if (err) { -+ log.error('Failed to load metadata:', err); -+ throw err; -+ } -+ try { -+ metadata = JSON.parse(bufferToString(data)); -+ } catch (e) { -+ log.error('Failed to parse JSON metadata from ' + metadataFile + ': ' + e); -+ throw e; -+ } -+ runServer(); -+ }); -+ } else { -+ runServer(); -+ } -+} -+ -+main(); -diff --git a/dist/source/debugger/duk_debugcommands.yaml b/dist/source/debugger/duk_debugcommands.yaml -new file mode 100644 -index 0000000..f253ba6 ---- /dev/null -+++ b/dist/source/debugger/duk_debugcommands.yaml -@@ -0,0 +1,52 @@ -+# Debug request/notify command names provided by the debug client. -+# These are concretely notify names now. -+client_commands: -+ - Reserved_0 -+ - Status -+ - Reserved_2 # Duktape 1.x: print notify -+ - Reserved_3 # Duktape 1.x: alert notify -+ - Reserved_4 # Duktape 1.x: log notify -+ - Throw -+ - Detaching -+ - AppNotify -+ -+# Debug request/notify command names provided by the debug target (Duktape). -+target_commands: -+ - Reserved_0 -+ - Reserved_1 -+ - Reserved_2 -+ - Reserved_3 -+ - Reserved_4 -+ - Reserved_5 -+ - Reserved_6 -+ - Reserved_7 -+ - Reserved_8 -+ - Reserved_9 -+ - Reserved_10 -+ - Reserved_11 -+ - Reserved_12 -+ - Reserved_13 -+ - Reserved_14 -+ - Reserved_15 -+ - BasicInfo -+ - TriggerStatus -+ - Pause -+ - Resume -+ - StepInto -+ - StepOver -+ - StepOut -+ - ListBreak -+ - AddBreak -+ - DelBreak -+ - GetVar -+ - PutVar -+ - GetCallStack -+ - GetLocals -+ - Eval -+ - Detach -+ - DumpHeap -+ - GetBytecode -+ - AppRequest -+ - GetHeapObjInfo -+ - GetObjPropDesc -+ - GetObjPropDescRange -diff --git a/dist/source/debugger/duk_debugerrors.yaml b/dist/source/debugger/duk_debugerrors.yaml -new file mode 100644 -index 0000000..500265f ---- /dev/null -+++ b/dist/source/debugger/duk_debugerrors.yaml -@@ -0,0 +1,6 @@ -+error_codes: -+ - Unknown -+ - UnsupportedCommand -+ - TooMany -+ - NotFound -+ - ApplicationError -diff --git a/dist/source/debugger/duk_opcodes.yaml b/dist/source/debugger/duk_opcodes.yaml -new file mode 100644 -index 0000000..d61bdba ---- /dev/null -+++ b/dist/source/debugger/duk_opcodes.yaml -@@ -0,0 +1,1193 @@ -+# Duktape opcode metadata for debugger. -+# - See duk_debug.js for the argument formats (A_R etc). -+# - Flag bits are for the whole instruction as a 32-bit integer, -+# they are not field shifted -+# -+# NOTE: Use YAML comments only on comment-only lines (not trailing content): -+# Node.js 'yamljs' seems to refuse parsing trailing comments in some cases. -+ -+opcodes: -+ - name: LDREG -+ args: -+ - A_R -+ - BC_R -+ - name: STREG -+ args: -+ - A_R -+ - BC_R -+ - name: JUMP -+ args: -+ - ABC_JUMP -+ - name: LDCONST -+ args: -+ - A_R -+ - BC_C -+ - name: LDINT -+ args: -+ - A_R -+ - BC_LDINT -+ - name: LDINTX -+ args: -+ - A_R -+ - BC_LDINTX -+ - name: LDTHIS -+ args: -+ - BC_R -+ - name: LDUNDEF -+ args: -+ - BC_R -+ - name: LDNULL -+ args: -+ - BC_R -+ - name: LDTRUE -+ args: -+ - BC_R -+ - name: LDFALSE -+ args: -+ - BC_R -+ - name: GETVAR -+ args: -+ - A_R -+ - BC_C -+ - name: BNOT -+ args: -+ - A_R -+ - BC_R -+ - name: LNOT -+ args: -+ - A_R -+ - BC_R -+ - name: UNM -+ args: -+ - A_R -+ - BC_R -+ - name: UNP -+ args: -+ - A_R -+ - BC_R -+ - name: EQ_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: EQ_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: EQ_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: EQ_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: NEQ_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: NEQ_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: NEQ_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: NEQ_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: SEQ_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: SEQ_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: SEQ_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: SEQ_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: SNEQ_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: SNEQ_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: SNEQ_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: SNEQ_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: GT_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: GT_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: GT_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: GT_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: GE_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: GE_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: GE_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: GE_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: LT_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: LT_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: LT_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: LT_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: LE_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: LE_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: LE_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: LE_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: IFTRUE_R -+ args: -+ - BC_R -+ - name: IFTRUE_C -+ args: -+ - BC_C -+ - name: IFFALSE_R -+ args: -+ - BC_R -+ - name: IFFALSE_C -+ args: -+ - BC_C -+ - name: ADD_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: ADD_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: ADD_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: ADD_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: SUB_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: SUB_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: SUB_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: SUB_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: MUL_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: MUL_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: MUL_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: MUL_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: DIV_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: DIV_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: DIV_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: DIV_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: MOD_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: MOD_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: MOD_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: MOD_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: EXP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: EXP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: EXP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: EXP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: BAND_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: BAND_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: BAND_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: BAND_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: BOR_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: BOR_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: BOR_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: BOR_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: BXOR_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: BXOR_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: BXOR_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: BXOR_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: BASL_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: BASL_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: BASL_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: BASL_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: BLSR_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: BLSR_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: BLSR_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: BLSR_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: BASR_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: BASR_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: BASR_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: BASR_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: INSTOF_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: INSTOF_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: INSTOF_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: INSTOF_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: IN_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: IN_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: IN_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: IN_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: GETPROP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: GETPROP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: GETPROP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: GETPROP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: PUTPROP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: PUTPROP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: PUTPROP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: PUTPROP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: DELPROP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: DELPROP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: DELPROP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: DELPROP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: PREINCR -+ args: -+ - A_R -+ - BC_R -+ - name: PREDECR -+ args: -+ - A_R -+ - BC_R -+ - name: POSTINCR -+ args: -+ - A_R -+ - BC_R -+ - name: POSTDECR -+ args: -+ - A_R -+ - BC_R -+ - name: PREINCV -+ args: -+ - A_R -+ - BC_C -+ - name: PREDECV -+ args: -+ - A_R -+ - BC_C -+ - name: POSTINCV -+ args: -+ - A_R -+ - BC_C -+ - name: POSTDECV -+ args: -+ - A_R -+ - BC_C -+ - name: PREINCP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: PREINCP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: PREINCP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: PREINCP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: PREDECP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: PREDECP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: PREDECP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: PREDECP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: POSTINCP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: POSTINCP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: POSTINCP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: POSTINCP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: POSTDECP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: POSTDECP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: POSTDECP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: POSTDECP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: DECLVAR_RR -+ args: -+ - A_H -+ - B_R -+ - C_R -+ flags: -+ - mask: 0x100 -+ name: writable -+ - mask: 0x200 -+ name: enumerable -+ - mask: 0x400 -+ name: configurable -+ - mask: 0x800 -+ name: accessor -+ - mask: 0x1000 -+ name: func_decl -+ - name: DECLVAR_CR -+ args: -+ - A_H -+ - B_C -+ - C_R -+ flags: -+ - mask: 0x100 -+ name: writable -+ - mask: 0x200 -+ name: enumerable -+ - mask: 0x400 -+ name: configurable -+ - mask: 0x800 -+ name: accessor -+ - mask: 0x1000 -+ name: func_decl -+ - name: DECLVAR_RC -+ args: -+ - A_H -+ - B_R -+ - C_C -+ flags: -+ - mask: 0x100 -+ name: writable -+ - mask: 0x200 -+ name: enumerable -+ - mask: 0x400 -+ name: configurable -+ - mask: 0x800 -+ name: accessor -+ - mask: 0x1000 -+ name: func_decl -+ - name: DECLVAR_CC -+ args: -+ - A_H -+ - B_C -+ - C_C -+ flags: -+ - mask: 0x100 -+ name: writable -+ - mask: 0x200 -+ name: enumerable -+ - mask: 0x400 -+ name: configurable -+ - mask: 0x800 -+ name: accessor -+ - mask: 0x1000 -+ name: func_decl -+ - name: REGEXP_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: REGEXP_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: REGEXP_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: REGEXP_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: CLOSURE -+ args: -+ - A_R -+ - BC_I -+ - name: TYPEOF -+ args: -+ - A_R -+ - BC_R -+ - name: TYPEOFID -+ args: -+ - A_R -+ - BC_C -+ - name: PUTVAR -+ args: -+ - A_R -+ - BC_C -+ - name: DELVAR -+ args: -+ - A_R -+ - BC_C -+ - name: RETREG -+ args: -+ - BC_R -+ - name: RETUNDEF -+ - name: RETCONST -+ args: -+ - BC_C -+ - name: RETCONSTN -+ args: -+ - BC_C -+ - name: LABEL -+ args: -+ - BC_I -+ - name: ENDLABEL -+ args: -+ - BC_I -+ - name: BREAK -+ args: -+ - BC_I -+ - name: CONTINUE -+ args: -+ - BC_I -+ - name: TRYCATCH -+ args: -+ - A_H -+ # base register for two consecutive regs (base_reg + 0, base_reg + 1) used for two things: -+ # - input: either 'with' target register or catch varname constant (base_reg + 0), depending on flags -+ # - output: when caught, catch value (base_reg + 0) and type (base_reg + 1) -+ - BC_R -+ flags: -+ - mask: 0x100 -+ name: have_catch -+ - mask: 0x200 -+ name: have_finally -+ - mask: 0x400 -+ name: catch_binding -+ - mask: 0x800 -+ name: with_binding -+ - name: ENDTRY -+ - name: ENDCATCH -+ - name: ENDFIN -+ args: -+ - ABC_R -+ - name: THROW -+ args: -+ - BC_R -+ - name: INVLHS -+ - name: CSREG -+ args: -+ - A_R -+ - BC_R -+ - name: CSVAR_RR -+ args: -+ - A_R -+ - B_R -+ - name: CSVAR_CR -+ args: -+ - A_R -+ - B_C -+ - name: CSVAR_RC -+ args: -+ - A_R -+ - B_R -+ - name: CSVAR_CC -+ args: -+ - A_R -+ - B_C -+ - name: CALL0 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL1 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL2 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL3 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL4 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL5 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL6 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL7 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL8 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL9 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL10 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL11 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL12 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL13 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL14 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: CALL15 -+ args: -+ - A_I -+ - BC_R -+ flags: -+ - mask: 0x01 -+ name: tailcall -+ - mask: 0x02 -+ name: construct -+ - mask: 0x04 -+ name: called_as_eval -+ - mask: 0x08 -+ name: indirect -+ - name: NEWOBJ -+ args: -+ - A_I # property count init size -+ - BC_R -+ - name: NEWARR -+ args: -+ - A_I # array item count init size -+ - BC_R -+ - name: MPUTOBJ -+ args: -+ - A_R -+ - B_R -+ - C_I -+ - name: MPUTOBJI -+ args: -+ - A_R -+ - B_RI -+ - C_I -+ - name: INITSET -+ args: -+ - A_R -+ - BC_R -+ - name: INITGET -+ args: -+ - A_R -+ - BC_R -+ - name: MPUTARR -+ args: -+ - A_R -+ - B_R -+ - C_I -+ - name: MPUTARRI -+ args: -+ - A_R -+ - B_RI -+ - C_I -+ - name: SETALEN -+ args: -+ - B_R -+ - C_R -+ - name: INITENUM -+ args: -+ - B_R -+ - C_R -+ - name: NEXTENUM -+ args: -+ - B_R -+ - C_R -+ - name: NEWTARGET -+ args: -+ - BC_R -+ - name: DEBUGGER -+ - name: NOP -+ args: -+ - ABC_I -+ - name: INVALID -+ args: -+ - ABC_I -+ - name: UNUSED207 -+ - name: GETPROPC_RR -+ args: -+ - A_R -+ - B_R -+ - C_R -+ - name: GETPROPC_CR -+ args: -+ - A_R -+ - B_C -+ - C_R -+ - name: GETPROPC_RC -+ args: -+ - A_R -+ - B_R -+ - C_C -+ - name: GETPROPC_CC -+ args: -+ - A_R -+ - B_C -+ - C_C -+ - name: UNUSED212 -+ - name: UNUSED213 -+ - name: UNUSED214 -+ - name: UNUSED215 -+ - name: UNUSED216 -+ - name: UNUSED217 -+ - name: UNUSED218 -+ - name: UNUSED219 -+ - name: UNUSED220 -+ - name: UNUSED221 -+ - name: UNUSED222 -+ - name: UNUSED223 -+ - name: UNUSED224 -+ - name: UNUSED225 -+ - name: UNUSED226 -+ - name: UNUSED227 -+ - name: UNUSED228 -+ - name: UNUSED229 -+ - name: UNUSED230 -+ - name: UNUSED231 -+ - name: UNUSED232 -+ - name: UNUSED233 -+ - name: UNUSED234 -+ - name: UNUSED235 -+ - name: UNUSED236 -+ - name: UNUSED237 -+ - name: UNUSED238 -+ - name: UNUSED239 -+ - name: UNUSED240 -+ - name: UNUSED241 -+ - name: UNUSED242 -+ - name: UNUSED243 -+ - name: UNUSED244 -+ - name: UNUSED245 -+ - name: UNUSED246 -+ - name: UNUSED247 -+ - name: UNUSED248 -+ - name: UNUSED249 -+ - name: UNUSED250 -+ - name: UNUSED251 -+ - name: UNUSED252 -+ - name: UNUSED253 -+ - name: UNUSED254 -+ - name: UNUSED255 -diff --git a/dist/source/debugger/package.json b/dist/source/debugger/package.json -new file mode 100644 -index 0000000..40fad19 ---- /dev/null -+++ b/dist/source/debugger/package.json -@@ -0,0 +1,27 @@ -+{ -+ "name": "duk-debug", -+ "version": "0.1.0", -+ "description": "Duktape debugger", -+ "author": { -+ "name": "Sami Vaarala", -+ "email": "sami.vaarala@iki.fi" -+ }, -+ "dependencies": { -+ "bluebird": "~2.6.4", -+ "body-parser": "~1.9.3", -+ "byline": "~4.2.1", -+ "events": "~1.0.2", -+ "express": "~4.10.1", -+ "http": "0.0.0", -+ "minimist": "~1.2.5", -+ "readline": "0.0.5", -+ "recursive-readdir-sync": "^1.0.6", -+ "socket.io": "~1.2.1", -+ "sprintf": "~0.1.5", -+ "stream": "0.0.2", -+ "utf8": "~2.0.0", -+ "util": "~0.10.3", -+ "yamljs": "~0.2.1" -+ }, -+ "main": "duk_debug.js" -+} -diff --git a/dist/source/debugger/static/index.html b/dist/source/debugger/static/index.html -new file mode 100644 -index 0000000..f77af7a ---- /dev/null -+++ b/dist/source/debugger/static/index.html -@@ -0,0 +1,96 @@ -+ -+ -+ -+ -+ -+ -+ -+Duktape debugger -+ -+ -+ -+
-+((o) Duktape debugger -+
-+ -+
-+ -+ -+ -+
-+

-+// No source loaded
-+
-+
-+
-+ -+
-+
-+
?
-+
?
?
-+
-+
-+
(output from script, print() and alert() calls)
-+
-+
-+ -+
-+
-+
(callstack)
-+
-+
-+
(locals)
-+
-+
-+
(breakpoints)
-+
-+
-+ watch (eval on pause) -+
-+ -+
-+
-+
-+ -+
-+ -+ -+ -+
-+

Duktape debugger is a web UI for debugging ECMAScript on a target device.

-+

This web UI talks to a NodeJS debug server using socket.io. -+The debug server talks to the target device using the Duktape debug protocol -+(see debugger.rst).

-+
-+ -+
-+

-+
-+ -+ -+ -+ -+ -+ -+ -diff --git a/dist/source/debugger/static/style.css b/dist/source/debugger/static/style.css -new file mode 100644 -index 0000000..1b6dd86 ---- /dev/null -+++ b/dist/source/debugger/static/style.css -@@ -0,0 +1,517 @@ -+// http://stackoverflow.com/questions/71074/how-to-remove-firefoxs-dotted-outline-on-buttons-as-well-as-links/3844452#3844452 -+:focus { -+ outline: none; -+} -+::-moz-focus-inner { -+ border: 0; -+} -+ -+@keyframes pulsate { -+ from { opacity: 1; } -+ to { opacity: 0.25; } -+} -+ -+#part-header { -+ background: #444444; -+ color: #ffffff; -+ font: 24pt monospace; -+ border-bottom: 2px solid #cccccc; -+ padding: 20px 0px 20px 10px; -+} -+ -+/* http://css-tricks.com/snippets/css/a-guide-to-flexbox/ */ -+#part-middle { -+ display: flex; -+ flex-direction: row; -+ flex-wrap: nowrap; -+ justify-content: space-between; -+ align-items: stretch; -+ align-content: stretch; -+ -+ min-height: 800px; -+ -+ border-top: 1px solid #ffffff; -+ padding: 8px; -+ margin-top: 2px; -+} -+#left-area { -+ flex: 0 0 11em; -+ margin-right: 20px; -+ margin-bottom: 10px; -+} -+#center-area { -+ flex: 1 1 0; -+ margin-bottom: 10px; -+} -+#right-area { -+ flex: 0 0 40em; -+ margin-left: 20px; -+ margin-bottom: 10px; -+} -+ -+#part-footer { -+ clear: both; -+ border-top: 2px solid #bbbbbb; -+ background: #eeeeee; -+ color: #555555; -+ text-align: center; -+ padding-top: 12px; -+ padding-bottom: 12px; -+ line-height: 1.5; -+} -+ -+#exec-status { -+ margin-top: 25px; -+ margin-bottom: 25px; -+} -+#exec-state { -+ display: inline-block; -+ vertical-align: middle; -+} -+#exec-other { -+ display: inline-block; -+ vertical-align: middle; -+ font-size: 125%; -+} -+#current-state { -+ background: #228822; -+ color: #ffffff; -+ font: 16pt; -+ padding: 6pt; -+ border: 5px solid #228822; -+ border-radius: 10px; -+ font-size: 200%; -+ font-weight: bold; -+ margin-right: 10px; -+} -+#current-state.notrunning { -+ background: #882222; -+ border: 5px solid #882222; -+ border-radius: 10px; -+ animation: pulsate 0.7s cubic-bezier(0.75, 0, 0.75, 1) infinite alternate; -+} -+#exec-other:hover { -+ text-decoration: underline; -+ color: #9999ff; -+} -+ -+#left-area .button { -+ display: inline-block; -+ text-align: center; -+ width: 95%; -+ min-width: 6em; -+ background: #226622; -+ color: #ffffff; -+ font: 16pt sans-serif; -+ font-weight: bold; -+ text-decoration: none; -+ margin: 10px 0 0 0; -+ padding: 0.4em; -+ border: 2px solid #000000; -+ border-radius: 4px; -+} -+#left-area .button a { -+ color: #ffffff; -+ text-decoration: none; -+} -+#left-area .button:hover { -+ background: #55aa55; -+} -+#left-area .button:disabled { -+ background: #555555; -+ color: #888888; -+} -+#left-area .button:disabled a { -+ background: #555555; -+ color: #888888; -+} -+ -+#pause-button.pending { -+ background: #5555ff; -+ animation: pulsate 0.2s cubic-bezier(0.75, 0, 0.75, 1) infinite alternate; -+} -+ -+#attach-button { -+} -+#attach-button.enabled { -+ animation: pulsate 0.7s cubic-bezier(0.75, 0, 0.75, 1) infinite alternate; -+} -+ -+.duktape-exec-line { -+ outline: 2px solid red; -+ background: #550000; -+} -+.duktape-break-line { -+ outline: 2px solid white; -+} -+ -+#output { -+ font: 9pt monospace; -+ color: #000000; -+ border: 2px solid #cccccc; -+ border-radius: 5px; -+ padding: 3px; -+ height: 30ex; -+ overflow: scroll; -+ overflow-x: auto; -+ overflow-y: scroll; -+ white-space: pre; -+} -+#output .alert { -+ color: #ff0000; -+} -+/* Default color (should be overridden by level) */ -+#output .log { -+ color: #00ff00; -+} -+/* Trace */ -+#output .loglevel0 { -+ color: #cccccc; -+} -+/* Debug */ -+#output .loglevel1 { -+ color: #cccccc; -+} -+/* Info */ -+#output .loglevel2 { -+ color: #888888; -+ font-weight: bold; -+} -+/* Warn */ -+#output .loglevel3 { -+ color: #ff4444; -+ font-weight: bold; -+} -+/* Error */ -+#output .loglevel4 { -+ color: #ff0000; -+ font-weight: bold; -+} -+/* Fatal */ -+#output .loglevel5 { -+ background: #000000; -+ color: #ff0000; -+ font-weight: bold; -+} -+#output .debugger-info { -+ color: #880000; -+ font-weight: bold; -+ font-style: italic; -+} -+#output .debugger-debug { -+ color: #888888; -+ font-weight: bold; -+ font-style: italic; -+} -+ -+#callstack { -+ font: 9pt monospace; -+ color: #000000; -+ margin-top: 10px; -+ border: 2px solid #cccccc; -+ border-radius: 5px; -+ padding: 3px; -+ height: 14ex; -+ overflow: scroll; -+ overflow-x: auto; -+ overflow-y: scroll; -+ white-space: pre; -+} -+#callstack div:nth-child(2n) { -+ background: #eeeeee; -+} -+#callstack .func { -+} -+#callstack .rest { -+ float: right; -+ color: #6666ff; -+} -+#callstack .rest:hover { -+ text-decoration: underline; -+ color: #9999ff; -+} -+ -+#locals { -+ font: 9pt monospace; -+ color: #000000; -+ margin-top: 10px; -+ border: 2px solid #cccccc; -+ border-radius: 5px; -+ padding: 10px; -+ height: 30ex; -+ overflow: scroll; -+ overflow-x: auto; -+ overflow-y: scroll; -+ white-space: pre; -+} -+#locals div:nth-child(2n) { -+ background: #eeeeee; -+} -+#locals .key { -+} -+#locals .value { -+ float: right; -+ color: #888888; -+} -+ -+#breakpoints { -+ color: #000000; -+ margin-top: 10px; -+ border: 2px solid #cccccc; -+ border-radius: 5px; -+ padding: 3px; -+ height: 15ex; -+ overflow: scroll; -+ overflow-x: auto; -+ overflow-y: scroll; -+ white-space: pre; -+} -+#breakpoints div { -+ margin: 2px 0 2px 0; -+} -+#breakpoints div:nth-child(2n) { -+ background: #eeeeee; -+} -+#breakpoints a { -+ font: 9pt monospace; -+ color: #6666ff; -+} -+#breakpoints a:hover { -+ text-decoration: underline; -+ color: #9999ff; -+} -+.breakpoint-line { -+ clear: both; -+ padding-top: 2px; -+ padding-bottom: 2px; -+} -+#add-breakpoint-file { -+ font: 10pt monospace; -+ width: 10em; -+ padding: 5px; -+} -+#add-breakpoint-line { -+ font: 10pt monospace; -+ width: 3em; -+ margin-left: 3px; -+ padding: 5px; -+} -+#delete-all-breakpoints-button { -+ float: right; -+ font: 10pt sans-serif; -+ padding: 5px; -+ border: 1px solid #888888; -+ background: #ddffdd; -+ color: #000000; -+} -+#delete-all-breakpoints-button:hover { -+ background: #f8fff8; -+} -+#delete-all-breakpoints-button:disabled { -+ background: #dddddd; -+ color: #444444; -+} -+#add-breakpoint-button { -+ font: 10pt sans-serif; -+ margin-left: 10px; -+ padding: 5px; -+ border: 1px solid #888888; -+ background: #ddffdd; -+ color: #000000; -+} -+#add-breakpoint-button:hover { -+ background: #f8fff8; -+} -+#add-breakpoint-button:disabled { -+ background: #dddddd; -+ color: #444444; -+} -+#breakpoint-hint { -+ color: #aaaaaa; -+ font-style: italic; -+ margin-left: 10px; -+} -+.delete-breakpoint-button { -+ float: right; -+ display: inline; -+ font: 9pt sans-serif; -+ padding: 3px; -+ border: none; -+ background: none; -+ color: #6666ff; -+} -+.delete-breakpoint-button { -+ font: 9pt sans-serif; -+} -+.delete-breakpoint-button:hover { -+ text-decoration: underline; -+ color: #9999ff; -+} -+.delete-breakpoint-button:disabled { -+ color: #888888; -+} -+ -+#about-dialog p { -+ margin: 10px 0 10px 0; -+} -+ -+#bytecode-dialog p { -+ margin: 10px 0 10px 0; -+} -+#bytecode-dialog pre { -+ font: 10pt monospace; -+ color: #000000; -+} -+#bytecode-dialog div.highlight { -+ background: #888888; -+ color: #ffffff; -+} -+ -+#eval { -+ color: #000000; -+ margin-top: 10px; -+ border: 2px solid #cccccc; -+ border-radius: 5px; -+ padding: 3px; -+ height: 30ex; -+ overflow: scroll; -+ overflow-x: auto; -+ overflow-y: scroll; -+ white-space: pre; -+} -+#eval-input { -+ display: inline; -+ font: 10pt monospace; -+ width: 20em; -+ padding: 5px; -+} -+#eval-button { -+ display: inline; -+ margin-left: 10px; -+ padding: 5px; -+ border: 1px solid #888888; -+ font: 10pt sans-serif; -+ background: #ddffdd; -+ color: #000000; -+} -+#eval-button { -+} -+#eval-button:hover { -+ background: #f8fff8; -+} -+#eval-button:disabled { -+ background: #dddddd; -+ color: #444444; -+} -+#eval-button.pending { -+ background: #5555ff; -+ animation: pulsate 0.2s cubic-bezier(0.75, 0, 0.75, 1) infinite alternate; -+} -+#eval-watch { -+ margin-left: 20px; -+ vertical-align: middle; -+} -+#eval-output { -+ font: 10pt monospace; -+ white-space: pre; -+ padding: 5px; -+ border: 1px solid #888888; -+ min-height: 4ex; -+ margin-top: 5px; -+} -+ -+#varname-input { -+ font: 10pt monospace; -+ width: 10em; -+ padding: 5px; -+} -+#varvalue-input { -+ margin-left: 10px; -+ font: 10pt monospace; -+ width: 20em; -+ padding: 5px; -+} -+#getvar-button, -+#putvar-button { -+ display: inline; -+ float: right; -+ margin-left: 10px; -+ padding: 5px; -+ border: 1px solid #888888; -+ font: 10pt sans-serif; -+ background: #ddffdd; -+ color: #000000; -+} -+#getvar-button:hover, -+#putvar-button:hover { -+ background: #f8fff8; -+} -+#getvar-button:disabled, -+#putvar-button:disabled { -+ background: #dddddd; -+ color: #444444; -+} -+#var-output { -+ font: 10pt monospace; -+ white-space: pre; -+ padding: 5px; -+ border: 1px solid #888888; -+ min-height: 4ex; -+ margin-top: 5px; -+} -+ -+#source-pre { -+ margin-top: 10px; -+ border: 2px solid #cccccc; -+ border-radius: 5px; -+ height: 400px; -+ overflow: scroll; -+ overflow-x: auto; -+ overflow-y: scroll; -+} -+#source-pre.running { -+ background: #eeeeee; -+ color: #888888; -+} -+#source-pre.running #source-code { -+ background: #eeeeee; -+ color: #888888; -+} -+#source-filename { -+ font-size: 125%; -+ color: #888888; -+} -+code.sourcecode { -+ counter-reset: source-line; -+} -+code.sourcecode div { -+ font: 10pt monospace; -+ padding: 2px 5px 2px 5px; -+ white-space: pre; -+ border-bottom: 1px solid #eeeeee; -+} -+code.sourcecode div:before { -+ display: inline-block; -+ content: counter(source-line); -+ counter-increment: source-line; -+ width: 4em; -+ color: #888888; -+ text-align: right; -+ margin-right: 20px; -+} -+code.sourcecode div.breakpoint:before { -+ margin-right: 0px; -+ border-right: 20px solid #ff0000; -+} -+code.sourcecode div.highlight { -+ background: #aaaaaa; -+ color: #000000; -+} -+code.sourcecode div.execution { -+ background: #000000; -+ color: #ffffff; -+} -+ -+#source-select { -+ margin-top: 5px; -+} -diff --git a/dist/source/debugger/static/webui.js b/dist/source/debugger/static/webui.js -new file mode 100644 -index 0000000..cb683f1 ---- /dev/null -+++ b/dist/source/debugger/static/webui.js -@@ -0,0 +1,808 @@ -+/* -+ * Duktape debugger web client -+ * -+ * Talks to the NodeJS server using socket.io. -+ * -+ * http://unixpapa.com/js/key.html -+ */ -+ -+// Update interval for custom source highlighting. -+var SOURCE_UPDATE_INTERVAL = 350; -+ -+// Source view -+var activeFileName = null; // file that we want to be loaded in source view -+var activeLine = null; // scroll to line once file has been loaded -+var activeHighlight = null; // line that we want to highlight (if any) -+var loadedFileName = null; // currently loaded (shown) file -+var loadedLineCount = 0; // currently loaded file line count -+var loadedFileExecuting = false; // true if currFileName (loosely) matches loadedFileName -+var loadedLinePending = null; // if set, scroll loaded file to requested line -+var highlightLine = null; // highlight line -+var sourceEditedLines = []; // line numbers which have been modified -+ // (added classes etc, tracked for removing) -+var sourceUpdateInterval = null; // timer for updating source view -+var sourceFetchXhr = null; // current AJAX request for fetching a source file (if any) -+var forceButtonUpdate = false; // hack to reset button states -+var bytecodeDialogOpen = false; // bytecode dialog active -+var bytecodeIdxHighlight = null; // index of currently highlighted line (or null) -+var bytecodeIdxInstr = 0; // index to first line of bytecode instructions -+ -+// Execution state -+var prevState = null; // previous execution state ('paused', 'running', etc) -+var prevAttached = null; // previous debugger attached state (true, false, null) -+var currFileName = null; // current filename being executed -+var currFuncName = null; // current function name being executed -+var currLine = 0; // current line being executed -+var currPc = 0; // current bytecode PC being executed -+var currState = 0; // current execution state ('paused', 'running', 'detached', etc) -+var currAttached = false; // current debugger attached state (true or false) -+var currLocals = []; // current local variables -+var currCallstack = []; // current callstack (from top to bottom) -+var currBreakpoints = []; // current breakpoints -+var startedRunning = 0; // timestamp when last started running (if running) -+ // (used to grey out the source file if running for long enough) -+ -+/* -+ * Helpers -+ */ -+ -+function formatBytes(x) { -+ if (x < 1024) { -+ return String(x) + ' bytes'; -+ } else if (x < 1024 * 1024) { -+ return (x / 1024).toPrecision(3) + ' kB'; -+ } else { -+ return (x / (1024 * 1024)).toPrecision(3) + ' MB'; -+ } -+} -+ -+/* -+ * Source view periodic update handling -+ */ -+ -+function doSourceUpdate() { -+ var elem; -+ -+ // Remove previously added custom classes -+ sourceEditedLines.forEach(function (linenum) { -+ elem = $('#source-code div')[linenum - 1]; -+ if (elem) { -+ elem.classList.remove('breakpoint'); -+ elem.classList.remove('execution'); -+ elem.classList.remove('highlight'); -+ } -+ }); -+ sourceEditedLines.length = 0; -+ -+ // If we're executing the file shown, highlight current line -+ if (loadedFileExecuting) { -+ elem = $('#source-code div')[currLine - 1]; -+ if (elem) { -+ sourceEditedLines.push(currLine); -+ elem.classList.add('execution'); -+ } -+ } -+ -+ // Add breakpoints -+ currBreakpoints.forEach(function (bp) { -+ if (bp.fileName === loadedFileName) { -+ elem = $('#source-code div')[bp.lineNumber - 1]; -+ if (elem) { -+ sourceEditedLines.push(bp.lineNumber); -+ elem.classList.add('breakpoint'); -+ } -+ } -+ }); -+ -+ if (highlightLine !== null) { -+ elem = $('#source-code div')[highlightLine - 1]; -+ if (elem) { -+ sourceEditedLines.push(highlightLine); -+ elem.classList.add('highlight'); -+ } -+ } -+ -+ // Bytecode dialog highlight -+ if (loadedFileExecuting && bytecodeDialogOpen && bytecodeIdxHighlight !== bytecodeIdxInstr + currPc) { -+ if (typeof bytecodeIdxHighlight === 'number') { -+ $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.remove('highlight'); -+ } -+ bytecodeIdxHighlight = bytecodeIdxInstr + currPc; -+ $('#bytecode-preformatted div')[bytecodeIdxHighlight].classList.add('highlight'); -+ } -+ -+ // If no-one requested us to scroll to a specific line, finish. -+ if (loadedLinePending == null) { -+ return; -+ } -+ -+ var reqLine = loadedLinePending; -+ loadedLinePending = null; -+ -+ // Scroll to requested line. This is not very clean, so a better solution -+ // should be found: -+ // https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollIntoView -+ // http://erraticdev.blogspot.fi/2011/02/jquery-scroll-into-view-plugin-with.html -+ // http://flesler.blogspot.fi/2007/10/jqueryscrollto.html -+ var tmpLine = Math.max(reqLine - 5, 0); -+ elem = $('#source-code div')[tmpLine]; -+ if (elem) { -+ elem.scrollIntoView(); -+ } -+} -+ -+// Source is updated periodically. Other code can also call doSourceUpdate() -+// directly if an immediate update is needed. -+sourceUpdateInterval = setInterval(doSourceUpdate, SOURCE_UPDATE_INTERVAL); -+ -+/* -+ * UI update handling when exec-status update arrives -+ */ -+ -+function doUiUpdate() { -+ var now = Date.now(); -+ -+ // Note: loadedFileName can be either from target or from server, but they -+ // must match exactly. We could do a loose match here, but exact matches -+ // are needed for proper breakpoint handling anyway. -+ loadedFileExecuting = (loadedFileName === currFileName); -+ -+ // If we just started running, store a timestamp so we can grey out the -+ // source view only if we execute long enough (i.e. we're not just -+ // stepping). -+ if (currState !== prevState && currState === 'running') { -+ startedRunning = now; -+ } -+ -+ // If we just became paused, check for eval watch -+ if (currState !== prevState && currState === 'paused') { -+ if ($('#eval-watch').is(':checked')) { -+ submitEval(); // don't clear eval input -+ } -+ } -+ -+ // Update current execution state -+ if (currFileName === '' && currLine === 0) { -+ $('#current-fileline').text(''); -+ } else { -+ $('#current-fileline').text(String(currFileName) + ':' + String(currLine)); -+ } -+ if (currFuncName === '' && currPc === 0) { -+ $('#current-funcpc').text(''); -+ } else { -+ $('#current-funcpc').text(String(currFuncName) + '() pc ' + String(currPc)); -+ } -+ $('#current-state').text(String(currState)); -+ -+ // Update buttons -+ if (currState !== prevState || currAttached !== prevAttached || forceButtonUpdate) { -+ $('#stepinto-button').prop('disabled', !currAttached || currState !== 'paused'); -+ $('#stepover-button').prop('disabled', !currAttached || currState !== 'paused'); -+ $('#stepout-button').prop('disabled', !currAttached || currState !== 'paused'); -+ $('#resume-button').prop('disabled', !currAttached || currState !== 'paused'); -+ $('#pause-button').prop('disabled', !currAttached || currState !== 'running'); -+ $('#attach-button').prop('disabled', currAttached); -+ if (currAttached) { -+ $('#attach-button').removeClass('enabled'); -+ } else { -+ $('#attach-button').addClass('enabled'); -+ } -+ $('#detach-button').prop('disabled', !currAttached); -+ $('#eval-button').prop('disabled', !currAttached); -+ $('#add-breakpoint-button').prop('disabled', !currAttached); -+ $('#delete-all-breakpoints-button').prop('disabled', !currAttached); -+ $('.delete-breakpoint-button').prop('disabled', !currAttached); -+ $('#putvar-button').prop('disabled', !currAttached); -+ $('#getvar-button').prop('disabled', !currAttached); -+ $('#heap-dump-download-button').prop('disabled', !currAttached); -+ } -+ if (currState !== 'running' || forceButtonUpdate) { -+ // Remove pending highlight once we're no longer running. -+ $('#pause-button').removeClass('pending'); -+ $('#eval-button').removeClass('pending'); -+ } -+ forceButtonUpdate = false; -+ -+ // Make source window grey when running for a longer time, use a small -+ // delay to avoid flashing grey when stepping. -+ if (currState === 'running' && now - startedRunning >= 500) { -+ $('#source-pre').removeClass('notrunning'); -+ $('#current-state').removeClass('notrunning'); -+ } else { -+ $('#source-pre').addClass('notrunning'); -+ $('#current-state').addClass('notrunning'); -+ } -+ -+ // Force source view to match currFileName only when running or when -+ // just became paused (from running or detached). -+ var fetchSource = false; -+ if (typeof currFileName === 'string') { -+ if (currState === 'running' || -+ (prevState !== 'paused' && currState === 'paused') || -+ (currAttached !== prevAttached)) { -+ if (activeFileName !== currFileName) { -+ fetchSource = true; -+ activeFileName = currFileName; -+ activeLine = currLine; -+ activeHighlight = null; -+ requestSourceRefetch(); -+ } -+ } -+ } -+ -+ // Force line update (scrollTop) only when running or just became paused. -+ // Otherwise let user browse and scroll source files freely. -+ if (!fetchSource) { -+ if ((prevState !== 'paused' && currState === 'paused') || -+ currState === 'running') { -+ loadedLinePending = currLine || 0; -+ } -+ } -+} -+ -+/* -+ * Init socket.io and add handlers -+ */ -+ -+var socket = io(); // returns a Manager -+ -+setInterval(function () { -+ socket.emit('keepalive', { -+ userAgent: (navigator || {}).userAgent -+ }); -+}, 30000); -+ -+socket.on('connect', function () { -+ $('#socketio-info').text('connected'); -+ currState = 'connected'; -+ -+ fetchSourceList(); -+}); -+socket.on('disconnect', function () { -+ $('#socketio-info').text('not connected'); -+ currState = 'disconnected'; -+}); -+socket.on('reconnecting', function () { -+ $('#socketio-info').text('reconnecting'); -+ currState = 'reconnecting'; -+}); -+socket.on('error', function (err) { -+ $('#socketio-info').text(err); -+}); -+ -+socket.on('replaced', function () { -+ // XXX: how to minimize the chance we'll further communciate with the -+ // server or reconnect to it? socket.reconnection()? -+ -+ // We'd like to window.close() here but can't (not allowed from scripts). -+ // Alert is the next best thing. -+ alert('Debugger connection replaced by a new one, do you have multiple tabs open? If so, please close this tab.'); -+}); -+ -+socket.on('keepalive', function (msg) { -+ // Not really interesting in the UI -+ // $('#server-info').text(new Date() + ': ' + JSON.stringify(msg)); -+}); -+ -+socket.on('basic-info', function (msg) { -+ $('#duk-version').text(String(msg.duk_version)); -+ $('#duk-git-describe').text(String(msg.duk_git_describe)); -+ $('#target-info').text(String(msg.target_info)); -+ $('#endianness').text(String(msg.endianness)); -+}); -+ -+socket.on('exec-status', function (msg) { -+ // Not 100% reliable if callstack has several functions of the same name -+ if (bytecodeDialogOpen && (currFileName != msg.fileName || currFuncName != msg.funcName)) { -+ socket.emit('get-bytecode', {}); -+ } -+ -+ currFileName = msg.fileName; -+ currFuncName = msg.funcName; -+ currLine = msg.line; -+ currPc = msg.pc; -+ currState = msg.state; -+ currAttached = msg.attached; -+ -+ // Duktape now restricts execution status updates quite effectively so -+ // there's no need to rate limit UI updates now. -+ -+ doUiUpdate(); -+ -+ prevState = currState; -+ prevAttached = currAttached; -+}); -+ -+// Update the "console" output based on lines sent by the server. The server -+// rate limits these updates to keep the browser load under control. Even -+// better would be for the client to pull this (and other stuff) on its own. -+socket.on('output-lines', function (msg) { -+ var elem = $('#output'); -+ var i, n, ent; -+ -+ elem.empty(); -+ for (i = 0, n = msg.length; i < n; i++) { -+ ent = msg[i]; -+ if (ent.type === 'print') { -+ elem.append($('
').text(ent.message)); -+ } else if (ent.type === 'alert') { -+ elem.append($('
').text(ent.message)); -+ } else if (ent.type === 'log') { -+ elem.append($('
').text(ent.message)); -+ } else if (ent.type === 'debugger-info') { -+ elem.append($('
').text(ent.message)); -+ } else if (ent.type === 'debugger-debug') { -+ elem.append($('
').text(ent.message)); -+ } else { -+ elem.append($('
').text(ent.message)); -+ } -+ } -+ -+ // http://stackoverflow.com/questions/14918787/jquery-scroll-to-bottom-of-div-even-after-it-updates -+ // Stop queued animations so that we always scroll quickly to bottom -+ $('#output').stop(true); -+ $('#output').animate({ scrollTop: $('#output')[0].scrollHeight}, 1000); -+}); -+ -+socket.on('callstack', function (msg) { -+ var elem = $('#callstack'); -+ var s1, s2, div; -+ -+ currCallstack = msg.callstack; -+ -+ elem.empty(); -+ msg.callstack.forEach(function (e) { -+ s1 = $('').text(e.fileName + ':' + e.lineNumber + ' (pc ' + e.pc + ')'); // float -+ s1.on('click', function () { -+ activeFileName = e.fileName; -+ activeLine = e.lineNumber || 1; -+ activeHighlight = activeLine; -+ requestSourceRefetch(); -+ }); -+ s2 = $('').text(e.funcName + '()'); -+ div = $('
'); -+ div.append(s1); -+ div.append(s2); -+ elem.append(div); -+ }); -+}); -+ -+socket.on('locals', function (msg) { -+ var elem = $('#locals'); -+ var s1, s2, div; -+ var i, n, e; -+ -+ currLocals = msg.locals; -+ -+ elem.empty(); -+ for (i = 0, n = msg.locals.length; i < n; i++) { -+ e = msg.locals[i]; -+ s1 = $('').text(e.value); // float -+ s2 = $('').text(e.key); -+ div = $('
'); -+ div.append(s1); -+ div.append(s2); -+ elem.append(div); -+ } -+}); -+ -+socket.on('debug-stats', function (msg) { -+ $('#debug-rx-bytes').text(formatBytes(msg.rxBytes)); -+ $('#debug-rx-dvalues').text(msg.rxDvalues); -+ $('#debug-rx-messages').text(msg.rxMessages); -+ $('#debug-rx-kbrate').text((msg.rxBytesPerSec / 1024).toFixed(2)); -+ $('#debug-tx-bytes').text(formatBytes(msg.txBytes)); -+ $('#debug-tx-dvalues').text(msg.txDvalues); -+ $('#debug-tx-messages').text(msg.txMessages); -+ $('#debug-tx-kbrate').text((msg.txBytesPerSec / 1024).toFixed(2)); -+}); -+ -+socket.on('breakpoints', function (msg) { -+ var elem = $('#breakpoints'); -+ var div; -+ var sub; -+ -+ currBreakpoints = msg.breakpoints; -+ -+ elem.empty(); -+ -+ // First line is special -+ div = $('
'); -+ sub = $('').text('Delete all breakpoints'); -+ sub.on('click', function () { -+ socket.emit('delete-all-breakpoints'); -+ }); -+ div.append(sub); -+ sub = $('').val('file.js'); -+ div.append(sub); -+ sub = $('').text(':'); -+ div.append(sub); -+ sub = $('').val('123'); -+ div.append(sub); -+ sub = $('').text('Add breakpoint'); -+ sub.on('click', function () { -+ socket.emit('add-breakpoint', { -+ fileName: $('#add-breakpoint-file').val(), -+ lineNumber: Number($('#add-breakpoint-line').val()) -+ }); -+ }); -+ div.append(sub); -+ sub = $('').text('or dblclick source'); -+ div.append(sub); -+ elem.append(div); -+ -+ // Active breakpoints follow -+ msg.breakpoints.forEach(function (bp) { -+ var div; -+ var sub; -+ -+ div = $('
'); -+ sub = $('').text('Delete'); -+ sub.on('click', function () { -+ socket.emit('delete-breakpoint', { -+ fileName: bp.fileName, -+ lineNumber: bp.lineNumber -+ }); -+ }); -+ div.append(sub); -+ sub = $('').text((bp.fileName || '?') + ':' + (bp.lineNumber || 0)); -+ sub.on('click', function () { -+ activeFileName = bp.fileName || ''; -+ activeLine = bp.lineNumber || 1; -+ activeHighlight = activeLine; -+ requestSourceRefetch(); -+ }); -+ div.append(sub); -+ elem.append(div); -+ }); -+ -+ forceButtonUpdate = true; -+ doUiUpdate(); -+}); -+ -+socket.on('eval-result', function (msg) { -+ $('#eval-output').text((msg.error ? 'ERROR: ' : '') + msg.result); -+ -+ // Remove eval button "pulsating" glow when we get a result -+ $('#eval-button').removeClass('pending'); -+}); -+ -+socket.on('getvar-result', function (msg) { -+ $('#var-output').text(msg.found ? msg.result : 'NOTFOUND'); -+}); -+ -+socket.on('bytecode', function (msg) { -+ var elem, div; -+ var div; -+ -+ elem = $('#bytecode-preformatted'); -+ elem.empty(); -+ -+ msg.preformatted.split('\n').forEach(function (line, idx) { -+ div = $('
'); -+ div.text(line); -+ elem.append(div); -+ }); -+ -+ bytecodeIdxHighlight = null; -+ bytecodeIdxInstr = msg.idxPreformattedInstructions; -+}); -+ -+$('#stepinto-button').click(function () { -+ socket.emit('stepinto', {}); -+}); -+ -+$('#stepover-button').click(function () { -+ socket.emit('stepover', {}); -+}); -+ -+$('#stepout-button').click(function () { -+ socket.emit('stepout', {}); -+}); -+ -+$('#pause-button').click(function () { -+ socket.emit('pause', {}); -+ -+ // Pause may take seconds to complete so indicate it is pending. -+ $('#pause-button').addClass('pending'); -+}); -+ -+$('#resume-button').click(function () { -+ socket.emit('resume', {}); -+}); -+ -+$('#attach-button').click(function () { -+ socket.emit('attach', {}); -+}); -+ -+$('#detach-button').click(function () { -+ socket.emit('detach', {}); -+}); -+ -+$('#about-button').click(function () { -+ $('#about-dialog').dialog('open'); -+}); -+ -+$('#show-bytecode-button').click(function () { -+ bytecodeDialogOpen = true; -+ $('#bytecode-dialog').dialog('open'); -+ -+ elem = $('#bytecode-preformatted'); -+ elem.empty().text('Loading bytecode...'); -+ -+ socket.emit('get-bytecode', {}); -+}); -+ -+function submitEval() { -+ socket.emit('eval', { input: $('#eval-input').val() }); -+ -+ // Eval may take seconds to complete so indicate it is pending. -+ $('#eval-button').addClass('pending'); -+} -+ -+$('#eval-button').click(function () { -+ submitEval(); -+ $('#eval-input').val(''); -+}); -+ -+$('#getvar-button').click(function () { -+ socket.emit('getvar', { varname: $('#varname-input').val() }); -+}); -+ -+$('#putvar-button').click(function () { -+ // The variable value is parsed as JSON right now, but it'd be better to -+ // also be able to parse buffer values etc. -+ var val = JSON.parse($('#varvalue-input').val()); -+ socket.emit('putvar', { varname: $('#varname-input').val(), varvalue: val }); -+}); -+ -+$('#source-code').dblclick(function (event) { -+ var target = event.target; -+ var elems = $('#source-code div'); -+ var i, n; -+ var line = 0; -+ -+ // XXX: any faster way; elems doesn't have e.g. indexOf() -+ for (i = 0, n = elems.length; i < n; i++) { -+ if (target === elems[i]) { -+ line = i + 1; -+ } -+ } -+ -+ socket.emit('toggle-breakpoint', { -+ fileName: loadedFileName, -+ lineNumber: line -+ }); -+}); -+ -+function setSourceText(data) { -+ var elem, div; -+ -+ elem = $('#source-code'); -+ elem.empty(); -+ data.split('\n').forEach(function (line) { -+ div = $('
'); -+ div.text(line); -+ elem.append(div); -+ }); -+ -+ sourceEditedLines = []; -+} -+ -+function setSourceSelect(fileName) { -+ var elem; -+ var i, n, t; -+ -+ if (fileName == null) { -+ $('#source-select').val('__none__'); -+ return; -+ } -+ -+ elem = $('#source-select option'); -+ for (i = 0, n = elem.length; i < n; i++) { -+ // Exact match is required. -+ t = $(elem[i]).val(); -+ if (t === fileName) { -+ $('#source-select').val(t); -+ return; -+ } -+ } -+} -+ -+/* -+ * AJAX request handling to fetch source files -+ */ -+ -+function requestSourceRefetch() { -+ // If previous update is pending, abort and start a new one. -+ if (sourceFetchXhr) { -+ sourceFetchXhr.abort(); -+ sourceFetchXhr = null; -+ } -+ -+ // Make copies of the requested file/line so that we have the proper -+ // values in case they've changed. -+ var fileName = activeFileName; -+ var lineNumber = activeLine; -+ -+ // AJAX request for the source. -+ sourceFetchXhr = $.ajax({ -+ type: 'POST', -+ url: '/source', -+ data: JSON.stringify({ fileName: fileName }), -+ contentType: 'application/json', -+ success: function (data, status, jqxhr) { -+ var elem; -+ -+ sourceFetchXhr = null; -+ -+ loadedFileName = fileName; -+ loadedLineCount = data.split('\n').length; // XXX: ignore issue with last empty line for now -+ loadedFileExecuting = (loadedFileName === currFileName); -+ setSourceText(data); -+ setSourceSelect(fileName); -+ loadedLinePending = activeLine || 1; -+ highlightLine = activeHighlight; // may be null -+ activeLine = null; -+ activeHighlight = null; -+ doSourceUpdate(); -+ -+ // XXX: hacky transition, make source change visible -+ $('#source-pre').fadeTo('fast', 0.25, function () { -+ $('#source-pre').fadeTo('fast', 1.0); -+ }); -+ }, -+ error: function (jqxhr, status, err) { -+ // Not worth alerting about because source fetch errors happen -+ // all the time, e.g. for dynamically evaluated code. -+ -+ sourceFetchXhr = null; -+ -+ // XXX: prevent retry of no-such-file by negative caching? -+ loadedFileName = fileName; -+ loadedLineCount = 1; -+ loadedFileExecuting = false; -+ setSourceText('// Cannot load source file: ' + fileName); -+ setSourceSelect(null); -+ loadedLinePending = 1; -+ activeLine = null; -+ activeHighlight = null; -+ doSourceUpdate(); -+ -+ // XXX: error transition here -+ $('#source-pre').fadeTo('fast', 0.25, function () { -+ $('#source-pre').fadeTo('fast', 1.0); -+ }); -+ }, -+ dataType: 'text' -+ }); -+} -+ -+/* -+ * AJAX request for fetching the source list -+ */ -+ -+function fetchSourceList() { -+ $.ajax({ -+ type: 'POST', -+ url: '/sourceList', -+ data: JSON.stringify({}), -+ contentType: 'application/json', -+ success: function (data, status, jqxhr) { -+ var elem = $('#source-select'); -+ -+ data = JSON.parse(data); -+ -+ elem.empty(); -+ var opt = $('').attr({ 'value': '__none__' }).text('No source file selected'); -+ elem.append(opt); -+ data.forEach(function (ent) { -+ var opt = $('').attr({ 'value': ent }).text(ent); -+ elem.append(opt); -+ }); -+ elem.change(function () { -+ activeFileName = elem.val(); -+ activeLine = 1; -+ requestSourceRefetch(); -+ }); -+ }, -+ error: function (jqxhr, status, err) { -+ // This is worth alerting about as the UI is somewhat unusable -+ // if we don't get a source list. -+ -+ alert('Failed to load source list: ' + err); -+ }, -+ dataType: 'text' -+ }); -+} -+ -+/* -+ * Initialization -+ */ -+ -+$(document).ready(function () { -+ var showAbout = true; -+ -+ // About dialog, shown automatically on first startup. -+ $('#about-dialog').dialog({ -+ autoOpen: false, -+ hide: 'fade', // puff -+ show: 'fade', // slide, puff -+ width: 500, -+ height: 300 -+ }); -+ -+ // Bytecode dialog -+ $('#bytecode-dialog').dialog({ -+ autoOpen: false, -+ hide: 'fade', // puff -+ show: 'fade', // slide, puff -+ width: 700, -+ height: 600, -+ close: function () { -+ bytecodeDialogOpen = false; -+ bytecodeIdxHighlight = null; -+ bytecodeIdxInstr = 0; -+ } -+ }); -+ -+ // http://diveintohtml5.info/storage.html -+ if (typeof localStorage !== 'undefined') { -+ if (localStorage.getItem('about-shown')) { -+ showAbout = false; -+ } else { -+ localStorage.setItem('about-shown', 'yes'); -+ } -+ } -+ if (showAbout) { -+ $('#about-dialog').dialog('open'); -+ } -+ -+ // onclick handler for exec status text -+ function loadCurrFunc() { -+ activeFileName = currFileName; -+ activeLine = currLine; -+ requestSourceRefetch(); -+ } -+ $('#exec-other').on('click', loadCurrFunc); -+ -+ // Enter handling for eval input -+ // https://forum.jquery.com/topic/bind-html-input-to-enter-key-keypress -+ $('#eval-input').keypress(function (event) { -+ if (event.keyCode == 13) { -+ submitEval(); -+ $('#eval-input').val(''); -+ } -+ }); -+ -+ // Eval watch handling -+ $('#eval-watch').change(function () { -+ // nop -+ }); -+ -+ // Function keys -+ $('body').keydown(function(e){ -+ //alert("keydown: "+e.which); -+ switch (e.which) { -+ case 116: // F5: step into -+ socket.emit('stepinto', {}); -+ e.preventDefault(); -+ return; -+ case 117: // F6: step over -+ socket.emit('stepover', {}); -+ e.preventDefault(); -+ return; -+ case 118: // F7: step out (= step return) -+ socket.emit('stepout', {}); -+ e.preventDefault(); -+ return; -+ case 119: // F8: resume -+ socket.emit('resume', {}); -+ e.preventDefault(); -+ return; -+ } -+ }); -+ -+ forceButtonUpdate = true; -+ doUiUpdate(); -+}); -diff --git a/dist/source/duk_dist_meta.json b/dist/source/duk_dist_meta.json -new file mode 100644 -index 0000000..b25abab ---- /dev/null -+++ b/dist/source/duk_dist_meta.json -@@ -0,0 +1,9 @@ -+{ -+ "comment": "Metadata for Duktape distributable", -+ "duk_version_string": "2.99.99", -+ "type": "duk_dist_meta", -+ "duk_version": 29999, -+ "git_branch": "master", -+ "git_commit": "65f1e02e580796929e92e91ba4776d4b0131beb5", -+ "git_describe": "65f1e02" -+} -\ No newline at end of file -diff --git a/dist/source/examples/README.rst b/dist/source/examples/README.rst -new file mode 100644 -index 0000000..5b876de ---- /dev/null -+++ b/dist/source/examples/README.rst -@@ -0,0 +1,10 @@ -+================ -+Duktape examples -+================ -+ -+Examples for using Duktape. These support user documentation and are -+intended as informative illustrations only. -+ -+Examples are unmaintained and are not production quality code. Bugs are -+not necessarily fixed, unless the bug makes the example misleading as -+documentation. -diff --git a/dist/source/examples/alloc-hybrid/README.rst b/dist/source/examples/alloc-hybrid/README.rst -new file mode 100644 -index 0000000..ed63a13 ---- /dev/null -+++ b/dist/source/examples/alloc-hybrid/README.rst -@@ -0,0 +1,10 @@ -+===================== -+Hybrid pool allocator -+===================== -+ -+Example allocator that tries to satisfy memory allocations for small sizes -+from a set of fixed pools, but always falls back to malloc/realloc/free if -+a larger size is requested or the pools have been exhausted. -+ -+This may be useful to reduce memory churn when the platform allocator does -+not handle allocations for a lot of small memory areas efficiently. -diff --git a/dist/source/examples/alloc-hybrid/duk_alloc_hybrid.c b/dist/source/examples/alloc-hybrid/duk_alloc_hybrid.c -new file mode 100644 -index 0000000..3f63249 ---- /dev/null -+++ b/dist/source/examples/alloc-hybrid/duk_alloc_hybrid.c -@@ -0,0 +1,294 @@ -+/* -+ * Example memory allocator with pool allocation for small sizes and -+ * fallback into malloc/realloc/free for larger sizes or when the pools -+ * are exhausted. -+ * -+ * Useful to reduce memory churn or work around a platform allocator -+ * that doesn't handle a lot of small allocations efficiently. -+ */ -+ -+#include "duktape.h" -+#include -+#include -+#include -+#include -+#include "duk_alloc_hybrid.h" -+ -+/* Define to enable some debug printfs. */ -+/* #define DUK_ALLOC_HYBRID_DEBUG */ -+ -+typedef struct { -+ size_t size; -+ int count; -+} pool_size_spec; -+ -+static pool_size_spec pool_sizes[] = { -+ { 32, 1024 }, -+ { 48, 2048 }, -+ { 64, 2048 }, -+ { 128, 2048 }, -+ { 256, 512 }, -+ { 1024, 64 }, -+ { 2048, 32 } -+}; -+ -+#define NUM_POOLS (sizeof(pool_sizes) / sizeof(pool_size_spec)) -+ -+/* This must fit into the smallest pool entry. */ -+struct pool_free_entry; -+typedef struct pool_free_entry pool_free_entry; -+struct pool_free_entry { -+ pool_free_entry *next; -+}; -+ -+typedef struct { -+ pool_free_entry *free; -+ char *alloc_start; -+ char *alloc_end; -+ size_t size; -+ int count; -+} pool_header; -+ -+typedef struct { -+ pool_header headers[NUM_POOLS]; -+ size_t pool_max_size; -+ char *alloc_start; -+ char *alloc_end; -+} pool_state; -+ -+#define ADDR_IN_STATE_ALLOC(st,p) \ -+ ((char *) (p) >= (st)->alloc_start && (char *) (p) < (st)->alloc_end) -+#define ADDR_IN_HEADER_ALLOC(hdr,p) \ -+ ((char *) (p) >= (hdr)->alloc_start && (char *) (p) < (hdr)->alloc_end) -+ -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+static void dump_pool_state(pool_state *st) { -+ pool_free_entry *free; -+ int free_len; -+ int i; -+ -+ printf("=== Pool state: st=%p\n", (void *) st); -+ for (i = 0; i < (int) NUM_POOLS; i++) { -+ pool_header *hdr = st->headers + i; -+ -+ for (free = hdr->free, free_len = 0; free != NULL; free = free->next) { -+ free_len++; -+ } -+ -+ printf("[%d]: size %ld, count %ld, used %ld, free list len %ld\n", -+ i, (long) hdr->size, (long) hdr->count, -+ (long) (hdr->count - free_len), -+ (long) free_len); -+ } -+} -+#else -+static void dump_pool_state(pool_state *st) { -+ (void) st; -+} -+#endif -+ -+void *duk_alloc_hybrid_init(void) { -+ pool_state *st; -+ size_t total_size, max_size; -+ int i, j; -+ char *p; -+ -+ st = (pool_state *) malloc(sizeof(pool_state)); -+ if (!st) { -+ return NULL; -+ } -+ memset((void *) st, 0, sizeof(pool_state)); -+ st->alloc_start = NULL; -+ st->alloc_end = NULL; -+ -+ for (i = 0, total_size = 0, max_size = 0; i < (int) NUM_POOLS; i++) { -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("Pool %d: size %ld, count %ld\n", i, (long) pool_sizes[i].size, (long) pool_sizes[i].count); -+#endif -+ total_size += pool_sizes[i].size * (size_t) pool_sizes[i].count; -+ if (pool_sizes[i].size > max_size) { -+ max_size = pool_sizes[i].size; -+ } -+ } -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("Total size %ld, max pool size %ld\n", (long) total_size, (long) max_size); -+#endif -+ -+ st->alloc_start = (char *) malloc(total_size); -+ if (!st->alloc_start) { -+ free(st); -+ return NULL; -+ } -+ st->alloc_end = st->alloc_start + total_size; -+ st->pool_max_size = max_size; -+ memset((void *) st->alloc_start, 0, total_size); -+ -+ for (i = 0, p = st->alloc_start; i < (int) NUM_POOLS; i++) { -+ pool_header *hdr = st->headers + i; -+ -+ hdr->alloc_start = p; -+ hdr->alloc_end = p + pool_sizes[i].size * (size_t) pool_sizes[i].count; -+ hdr->free = (pool_free_entry *) (void *) p; -+ hdr->size = pool_sizes[i].size; -+ hdr->count = pool_sizes[i].count; -+ -+ for (j = 0; j < pool_sizes[i].count; j++) { -+ pool_free_entry *ent = (pool_free_entry *) (void *) p; -+ if (j == pool_sizes[i].count - 1) { -+ ent->next = (pool_free_entry *) NULL; -+ } else { -+ ent->next = (pool_free_entry *) (void *) (p + pool_sizes[i].size); -+ } -+ p += pool_sizes[i].size; -+ } -+ } -+ -+ dump_pool_state(st); -+ -+ /* Use 'st' as udata. */ -+ return (void *) st; -+} -+ -+void *duk_alloc_hybrid(void *udata, duk_size_t size) { -+ pool_state *st = (pool_state *) udata; -+ int i; -+ void *new_ptr; -+ -+#if 0 -+ dump_pool_state(st); -+#endif -+ -+ if (size == 0) { -+ return NULL; -+ } -+ if (size > st->pool_max_size) { -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("alloc fallback: %ld\n", (long) size); -+#endif -+ return malloc(size); -+ } -+ -+ for (i = 0; i < (int) NUM_POOLS; i++) { -+ pool_header *hdr = st->headers + i; -+ if (hdr->size < size) { -+ continue; -+ } -+ -+ if (hdr->free) { -+#if 0 -+ printf("alloc from pool: %ld -> pool size %ld\n", (long) size, (long) hdr->size); -+#endif -+ new_ptr = (void *) hdr->free; -+ hdr->free = hdr->free->next; -+ return new_ptr; -+ } else { -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("alloc out of pool entries: %ld -> pool size %ld\n", (long) size, (long) hdr->size); -+#endif -+ break; -+ } -+ } -+ -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("alloc fallback (out of pool): %ld\n", (long) size); -+#endif -+ return malloc(size); -+} -+ -+void *duk_realloc_hybrid(void *udata, void *ptr, duk_size_t size) { -+ pool_state *st = (pool_state *) udata; -+ void *new_ptr; -+ int i; -+ -+#if 0 -+ dump_pool_state(st); -+#endif -+ -+ if (ADDR_IN_STATE_ALLOC(st, ptr)) { -+ /* 'ptr' cannot be NULL. */ -+ for (i = 0; i < (int) NUM_POOLS; i++) { -+ pool_header *hdr = st->headers + i; -+ if (ADDR_IN_HEADER_ALLOC(hdr, ptr)) { -+ if (size <= hdr->size) { -+ /* Still fits, no shrink support. */ -+#if 0 -+ printf("realloc original from pool: still fits, size %ld, pool size %ld\n", -+ (long) size, (long) hdr->size); -+#endif -+ return ptr; -+ } -+ -+ new_ptr = duk_alloc_hybrid(udata, size); -+ if (!new_ptr) { -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("realloc original from pool: needed larger size, failed to alloc\n"); -+#endif -+ return NULL; -+ } -+ memcpy(new_ptr, ptr, hdr->size); -+ -+ ((pool_free_entry *) ptr)->next = hdr->free; -+ hdr->free = (pool_free_entry *) ptr; -+#if 0 -+ printf("realloc original from pool: size %ld, pool size %ld\n", (long) size, (long) hdr->size); -+#endif -+ return new_ptr; -+ } -+ } -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("NEVER HERE\n"); -+#endif -+ return NULL; -+ } else if (ptr != NULL) { -+ if (size == 0) { -+ free(ptr); -+ return NULL; -+ } else { -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("realloc fallback: size %ld\n", (long) size); -+#endif -+ return realloc(ptr, size); -+ } -+ } else { -+#if 0 -+ printf("realloc NULL ptr, call alloc: %ld\n", (long) size); -+#endif -+ return duk_alloc_hybrid(udata, size); -+ } -+} -+ -+void duk_free_hybrid(void *udata, void *ptr) { -+ pool_state *st = (pool_state *) udata; -+ int i; -+ -+#if 0 -+ dump_pool_state(st); -+#endif -+ -+ if (!ADDR_IN_STATE_ALLOC(st, ptr)) { -+ if (ptr == NULL) { -+ return; -+ } -+#if 0 -+ printf("free out of pool: %p\n", (void *) ptr); -+#endif -+ free(ptr); -+ return; -+ } -+ -+ for (i = 0; i < (int) NUM_POOLS; i++) { -+ pool_header *hdr = st->headers + i; -+ if (ADDR_IN_HEADER_ALLOC(hdr, ptr)) { -+ ((pool_free_entry *) ptr)->next = hdr->free; -+ hdr->free = (pool_free_entry *) ptr; -+#if 0 -+ printf("free from pool: %p\n", ptr); -+#endif -+ return; -+ } -+ } -+ -+#if defined(DUK_ALLOC_HYBRID_DEBUG) -+ printf("NEVER HERE\n"); -+#endif -+} -diff --git a/dist/source/examples/alloc-hybrid/duk_alloc_hybrid.h b/dist/source/examples/alloc-hybrid/duk_alloc_hybrid.h -new file mode 100644 -index 0000000..d8c09e9 ---- /dev/null -+++ b/dist/source/examples/alloc-hybrid/duk_alloc_hybrid.h -@@ -0,0 +1,11 @@ -+#if !defined(DUK_ALLOC_HYBRID_H_INCLUDED) -+#define DUK_ALLOC_HYBRID_H_INCLUDED -+ -+#include "duktape.h" -+ -+void *duk_alloc_hybrid_init(void); -+void *duk_alloc_hybrid(void *udata, duk_size_t size); -+void *duk_realloc_hybrid(void *udata, void *ptr, duk_size_t size); -+void duk_free_hybrid(void *udata, void *ptr); -+ -+#endif /* DUK_ALLOC_HYBRID_H_INCLUDED */ -diff --git a/dist/source/examples/alloc-logging/README.rst b/dist/source/examples/alloc-logging/README.rst -new file mode 100644 -index 0000000..97c1a32 ---- /dev/null -+++ b/dist/source/examples/alloc-logging/README.rst -@@ -0,0 +1,7 @@ -+====================== -+Allocator with logging -+====================== -+ -+Example allocator that writes all memory alloc/realloc/free calls into a -+log file so that memory usage can replayed later. This is useful to e.g. -+optimize pool sizes. -diff --git a/dist/source/examples/alloc-logging/duk_alloc_logging.c b/dist/source/examples/alloc-logging/duk_alloc_logging.c -new file mode 100644 -index 0000000..b78fde4 ---- /dev/null -+++ b/dist/source/examples/alloc-logging/duk_alloc_logging.c -@@ -0,0 +1,139 @@ -+/* -+ * Example memory allocator with machine parseable logging. -+ * -+ * Also sizes for reallocs and frees are logged so that the memory -+ * behavior can be essentially replayed to accurately determine e.g. -+ * optimal pool sizes for a pooled allocator. -+ * -+ * Allocation structure: -+ * -+ * [ alloc_hdr | user area ] -+ * -+ * ^ ^ -+ * | `--- pointer returned to Duktape -+ * `--- underlying malloc ptr -+ */ -+ -+#include "duktape.h" -+#include -+#include -+#include -+#include -+#include "duk_alloc_logging.h" -+ -+#define ALLOC_LOG_FILE "/tmp/duk-alloc-log.txt" -+ -+typedef struct { -+ /* The double value in the union is there to ensure alignment is -+ * good for IEEE doubles too. In many 32-bit environments 4 bytes -+ * would be sufficiently aligned and the double value is unnecessary. -+ */ -+ union { -+ size_t sz; -+ double d; -+ } u; -+} alloc_hdr; -+ -+static FILE *log_file = NULL; -+ -+static void write_log(const char *fmt, ...) { -+ va_list ap; -+ -+ if (!log_file) { -+ log_file = fopen(ALLOC_LOG_FILE, "wb"); -+ if (!log_file) { -+ return; -+ } -+ } -+ -+ va_start(ap, fmt); -+ vfprintf(log_file, fmt, ap); -+ va_end(ap); -+} -+ -+void *duk_alloc_logging(void *udata, duk_size_t size) { -+ alloc_hdr *hdr; -+ void *ret; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ if (size == 0) { -+ write_log("A NULL %ld\n", (long) size); -+ return NULL; -+ } -+ -+ hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr)); -+ if (!hdr) { -+ write_log("A FAIL %ld\n", (long) size); -+ return NULL; -+ } -+ hdr->u.sz = size; -+ ret = (void *) (hdr + 1); -+ write_log("A %p %ld\n", ret, (long) size); -+ return ret; -+} -+ -+void *duk_realloc_logging(void *udata, void *ptr, duk_size_t size) { -+ alloc_hdr *hdr; -+ size_t old_size; -+ void *t; -+ void *ret; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ /* Handle the ptr-NULL vs. size-zero cases explicitly to minimize -+ * platform assumptions. You can get away with much less in specific -+ * well-behaving environments. -+ */ -+ -+ if (ptr) { -+ hdr = (alloc_hdr *) (void *) ((unsigned char *) ptr - sizeof(alloc_hdr)); -+ old_size = hdr->u.sz; -+ -+ if (size == 0) { -+ write_log("R %p %ld NULL 0\n", ptr, (long) old_size); -+ free((void *) hdr); -+ return NULL; -+ } else { -+ t = realloc((void *) hdr, size + sizeof(alloc_hdr)); -+ if (!t) { -+ write_log("R %p %ld FAIL %ld\n", ptr, (long) old_size, (long) size); -+ return NULL; -+ } -+ hdr = (alloc_hdr *) t; -+ hdr->u.sz = size; -+ ret = (void *) (hdr + 1); -+ write_log("R %p %ld %p %ld\n", ptr, (long) old_size, ret, (long) size); -+ return ret; -+ } -+ } else { -+ if (size == 0) { -+ write_log("R NULL 0 NULL 0\n"); -+ return NULL; -+ } else { -+ hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr)); -+ if (!hdr) { -+ write_log("R NULL 0 FAIL %ld\n", (long) size); -+ return NULL; -+ } -+ hdr->u.sz = size; -+ ret = (void *) (hdr + 1); -+ write_log("R NULL 0 %p %ld\n", ret, (long) size); -+ return ret; -+ } -+ } -+} -+ -+void duk_free_logging(void *udata, void *ptr) { -+ alloc_hdr *hdr; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ if (!ptr) { -+ write_log("F NULL 0\n"); -+ return; -+ } -+ hdr = (alloc_hdr *) (void *) ((unsigned char *) ptr - sizeof(alloc_hdr)); -+ write_log("F %p %ld\n", ptr, (long) hdr->u.sz); -+ free((void *) hdr); -+} -diff --git a/dist/source/examples/alloc-logging/duk_alloc_logging.h b/dist/source/examples/alloc-logging/duk_alloc_logging.h -new file mode 100644 -index 0000000..a496c29 ---- /dev/null -+++ b/dist/source/examples/alloc-logging/duk_alloc_logging.h -@@ -0,0 +1,10 @@ -+#if !defined(DUK_ALLOC_LOGGING_H_INCLUDED) -+#define DUK_ALLOC_LOGGING_H_INCLUDED -+ -+#include "duktape.h" -+ -+void *duk_alloc_logging(void *udata, duk_size_t size); -+void *duk_realloc_logging(void *udata, void *ptr, duk_size_t size); -+void duk_free_logging(void *udata, void *ptr); -+ -+#endif /* DUK_ALLOC_LOGGING_H_INCLUDED */ -diff --git a/dist/source/examples/alloc-logging/log2gnuplot.py b/dist/source/examples/alloc-logging/log2gnuplot.py -new file mode 100644 -index 0000000..7a009f2 ---- /dev/null -+++ b/dist/source/examples/alloc-logging/log2gnuplot.py -@@ -0,0 +1,41 @@ -+#!/usr/bin/env python2 -+# -+# Analyze allocator logs and write total-bytes-in-use after every -+# operation to stdout. The output can be gnuplotted as: -+# -+# $ python log2gnuplot.py /tmp/output.txt -+# $ gnuplot -+# > plot "output.txt" with lines -+# -+ -+import os -+import sys -+ -+def main(): -+ allocated = 0 -+ -+ for line in sys.stdin: -+ line = line.strip() -+ parts = line.split(' ') -+ -+ # A ptr/NULL/FAIL size -+ # F ptr/NULL size -+ # R ptr/NULL oldsize ptr/NULL/FAIL newsize -+ -+ # Note: duk-low doesn't log oldsize (uses -1 instead) -+ -+ if parts[0] == 'A': -+ if parts[1] != 'NULL' and parts[1] != 'FAIL': -+ allocated += long(parts[2]) -+ elif parts[0] == 'F': -+ allocated -= long(parts[2]) -+ elif parts[0] == 'R': -+ allocated -= long(parts[2]) -+ if parts[3] != 'NULL' and parts[3] != 'FAIL': -+ allocated += long(parts[4]) -+ print(allocated) -+ -+ print(allocated) -+ -+if __name__ == '__main__': -+ main() -diff --git a/dist/source/examples/alloc-torture/README.rst b/dist/source/examples/alloc-torture/README.rst -new file mode 100644 -index 0000000..f3278bb ---- /dev/null -+++ b/dist/source/examples/alloc-torture/README.rst -@@ -0,0 +1,10 @@ -+========================================== -+Allocator with memory wiping and red zones -+========================================== -+ -+Example allocator that wipes memory on free and checks that no out-of-bounds -+writes have been made to bytes just before and after the allocated area. -+ -+Valgrind is a better tool for detecting these memory issues, but it's not -+available for all targets so you can use something like this to detect -+memory lifecycle or out-of-bounds issues. -diff --git a/dist/source/examples/alloc-torture/duk_alloc_torture.c b/dist/source/examples/alloc-torture/duk_alloc_torture.c -new file mode 100644 -index 0000000..fd1dbe3 ---- /dev/null -+++ b/dist/source/examples/alloc-torture/duk_alloc_torture.c -@@ -0,0 +1,183 @@ -+/* -+ * Example torture memory allocator with memory wiping and check for -+ * out-of-bounds writes. -+ * -+ * Allocation structure: -+ * -+ * [ alloc_hdr | red zone before | user area | red zone after ] -+ * -+ * ^ ^ -+ * | `--- pointer returned to Duktape -+ * `--- underlying malloc ptr -+ */ -+ -+#include "duktape.h" -+#include -+#include -+#include -+#include -+#include "duk_alloc_torture.h" -+ -+#define RED_ZONE_SIZE 16 -+#define RED_ZONE_BYTE 0x5a -+#define INIT_BYTE 0xa5 -+#define WIPE_BYTE 0x27 -+ -+typedef struct { -+ /* The double value in the union is there to ensure alignment is -+ * good for IEEE doubles too. In many 32-bit environments 4 bytes -+ * would be sufficiently aligned and the double value is unnecessary. -+ */ -+ union { -+ size_t sz; -+ double d; -+ } u; -+} alloc_hdr; -+ -+static void check_red_zone(alloc_hdr *hdr) { -+ size_t size; -+ int i; -+ int err; -+ unsigned char *p; -+ unsigned char *userptr; -+ -+ size = hdr->u.sz; -+ userptr = (unsigned char *) hdr + sizeof(alloc_hdr) + RED_ZONE_SIZE; -+ -+ err = 0; -+ p = (unsigned char *) hdr + sizeof(alloc_hdr); -+ for (i = 0; i < RED_ZONE_SIZE; i++) { -+ if (p[i] != RED_ZONE_BYTE) { -+ err = 1; -+ } -+ } -+ if (err) { -+ fprintf(stderr, "RED ZONE CORRUPTED BEFORE ALLOC: hdr=%p ptr=%p size=%ld\n", -+ (void *) hdr, (void *) userptr, (long) size); -+ fflush(stderr); -+ } -+ -+ err = 0; -+ p = (unsigned char *) hdr + sizeof(alloc_hdr) + RED_ZONE_SIZE + size; -+ for (i = 0; i < RED_ZONE_SIZE; i++) { -+ if (p[i] != RED_ZONE_BYTE) { -+ err = 1; -+ } -+ } -+ if (err) { -+ fprintf(stderr, "RED ZONE CORRUPTED AFTER ALLOC: hdr=%p ptr=%p size=%ld\n", -+ (void *) hdr, (void *) userptr, (long) size); -+ fflush(stderr); -+ } -+} -+ -+void *duk_alloc_torture(void *udata, duk_size_t size) { -+ unsigned char *p; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ if (size == 0) { -+ return NULL; -+ } -+ -+ p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); -+ if (!p) { -+ return NULL; -+ } -+ -+ ((alloc_hdr *) (void *) p)->u.sz = size; -+ p += sizeof(alloc_hdr); -+ memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); -+ p += RED_ZONE_SIZE; -+ memset((void *) p, INIT_BYTE, size); -+ p += size; -+ memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); -+ p -= size; -+ return (void *) p; -+} -+ -+void *duk_realloc_torture(void *udata, void *ptr, duk_size_t size) { -+ unsigned char *p, *old_p; -+ size_t old_size; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ /* Handle the ptr-NULL vs. size-zero cases explicitly to minimize -+ * platform assumptions. You can get away with much less in specific -+ * well-behaving environments. -+ */ -+ -+ if (ptr) { -+ old_p = (unsigned char *) ptr - sizeof(alloc_hdr) - RED_ZONE_SIZE; -+ old_size = ((alloc_hdr *) (void *) old_p)->u.sz; -+ check_red_zone((alloc_hdr *) (void *) old_p); -+ -+ if (size == 0) { -+ memset((void *) old_p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); -+ free((void *) old_p); -+ return NULL; -+ } else { -+ /* Force address change on every realloc. */ -+ p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); -+ if (!p) { -+ return NULL; -+ } -+ -+ ((alloc_hdr *) (void *) p)->u.sz = size; -+ p += sizeof(alloc_hdr); -+ memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); -+ p += RED_ZONE_SIZE; -+ if (size > old_size) { -+ memcpy((void *) p, (void *) (old_p + sizeof(alloc_hdr) + RED_ZONE_SIZE), old_size); -+ memset((void *) (p + old_size), INIT_BYTE, size - old_size); -+ } else { -+ memcpy((void *) p, (void *) (old_p + sizeof(alloc_hdr) + RED_ZONE_SIZE), size); -+ } -+ p += size; -+ memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); -+ p -= size; -+ -+ memset((void *) old_p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); -+ free((void *) old_p); -+ -+ return (void *) p; -+ } -+ } else { -+ if (size == 0) { -+ return NULL; -+ } else { -+ p = (unsigned char *) malloc(size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); -+ if (!p) { -+ return NULL; -+ } -+ -+ ((alloc_hdr *) (void *) p)->u.sz = size; -+ p += sizeof(alloc_hdr); -+ memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); -+ p += RED_ZONE_SIZE; -+ memset((void *) p, INIT_BYTE, size); -+ p += size; -+ memset((void *) p, RED_ZONE_BYTE, RED_ZONE_SIZE); -+ p -= size; -+ return (void *) p; -+ } -+ } -+} -+ -+void duk_free_torture(void *udata, void *ptr) { -+ unsigned char *p; -+ size_t old_size; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ if (!ptr) { -+ return; -+ } -+ -+ p = (unsigned char *) ptr - sizeof(alloc_hdr) - RED_ZONE_SIZE; -+ old_size = ((alloc_hdr *) (void *) p)->u.sz; -+ -+ check_red_zone((alloc_hdr *) (void *) p); -+ memset((void *) p, WIPE_BYTE, old_size + sizeof(alloc_hdr) + 2 * RED_ZONE_SIZE); -+ free((void *) p); -+} -diff --git a/dist/source/examples/alloc-torture/duk_alloc_torture.h b/dist/source/examples/alloc-torture/duk_alloc_torture.h -new file mode 100644 -index 0000000..0b36b69 ---- /dev/null -+++ b/dist/source/examples/alloc-torture/duk_alloc_torture.h -@@ -0,0 +1,10 @@ -+#if !defined(DUK_ALLOC_TORTURE_H_INCLUDED) -+#define DUK_ALLOC_TORTURE_H_INCLUDED -+ -+#include "duktape.h" -+ -+void *duk_alloc_torture(void *udata, duk_size_t size); -+void *duk_realloc_torture(void *udata, void *ptr, duk_size_t size); -+void duk_free_torture(void *udata, void *ptr); -+ -+#endif /* DUK_ALLOC_TORTURE_H_INCLUDED */ -diff --git a/dist/source/examples/cmdline/README.rst b/dist/source/examples/cmdline/README.rst -new file mode 100644 -index 0000000..825eec9 ---- /dev/null -+++ b/dist/source/examples/cmdline/README.rst -@@ -0,0 +1,6 @@ -+==================== -+Duktape command line -+==================== -+ -+ECMAScript command line execution tool, useful for running ECMAScript code -+from a file, stdin, or interactively. Also used by automatic testing. -diff --git a/dist/source/examples/cmdline/duk_cmdline.c b/dist/source/examples/cmdline/duk_cmdline.c -new file mode 100644 -index 0000000..01a5794 ---- /dev/null -+++ b/dist/source/examples/cmdline/duk_cmdline.c -@@ -0,0 +1,1867 @@ -+/* -+ * Command line execution tool. Useful for test cases and manual testing. -+ * Also demonstrates some basic integration techniques. -+ * -+ * Optional features include: -+ * -+ * - To enable print()/alert() bindings, define DUK_CMDLINE_PRINTALERT_SUPPORT -+ * and add extras/print-alert/duk_print_alert.c to compilation. -+ * -+ * - To enable console.log() etc, define DUK_CMDLINE_CONSOLE_SUPPORT -+ * and add extras/console/duk_console.c to compilation. -+ * -+ * - To enable Duktape.Logger, define DUK_CMDLINE_LOGGING_SUPPORT -+ * and add extras/logging/duk_logging.c to compilation. -+ * -+ * - To enable Duktape 1.x module loading support (require(), -+ * Duktape.modSearch() etc), define DUK_CMDLINE_MODULE_SUPPORT and add -+ * extras/module-duktape/duk_module_duktape.c to compilation. -+ * -+ * - To enable linenoise and other fancy stuff, compile with -DDUK_CMDLINE_FANCY. -+ * It is not the default to maximize portability. You can also compile in -+ * support for example allocators, grep for DUK_CMDLINE_*. -+ */ -+ -+/* Helper define to enable a feature set; can also use separate defines. */ -+#if defined(DUK_CMDLINE_FANCY) -+#define DUK_CMDLINE_LINENOISE -+#define DUK_CMDLINE_LINENOISE_COMPLETION /* Enables completion and hints. */ -+#define DUK_CMDLINE_RLIMIT -+#define DUK_CMDLINE_SIGNAL -+#endif -+ -+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \ -+ defined(WIN64) || defined(_WIN64) || defined(__WIN64__) -+/* Suppress warnings about plain fopen() etc. */ -+#define _CRT_SECURE_NO_WARNINGS -+#if defined(_MSC_VER) && (_MSC_VER < 1900) -+/* Workaround for snprintf() missing in older MSVC versions. -+ * Note that _snprintf() may not NUL terminate the string, but -+ * this difference does not matter here as a NUL terminator is -+ * always explicitly added. -+ */ -+#define snprintf _snprintf -+#endif -+#endif -+ -+#if defined(DUK_CMDLINE_PTHREAD_STACK_CHECK) -+#define _GNU_SOURCE -+#include -+#endif -+ -+#include -+#include -+#include -+#if defined(DUK_CMDLINE_SIGNAL) -+#include -+#endif -+#if defined(DUK_CMDLINE_RLIMIT) -+#include -+#endif -+#if defined(DUK_CMDLINE_LINENOISE) -+#include "linenoise.h" -+#include /* Assume C99/C++11 with linenoise. */ -+#endif -+#if defined(DUK_CMDLINE_PRINTALERT_SUPPORT) -+#include "duk_print_alert.h" -+#endif -+#if defined(DUK_CMDLINE_CONSOLE_SUPPORT) -+#include "duk_console.h" -+#endif -+#if defined(DUK_CMDLINE_LOGGING_SUPPORT) -+#include "duk_logging.h" -+#endif -+#if defined(DUK_CMDLINE_MODULE_SUPPORT) -+#include "duk_module_duktape.h" -+#endif -+#if defined(DUK_CMDLINE_FILEIO) -+#include -+#endif -+#if defined(EMSCRIPTEN) -+#include -+#endif -+#if defined(DUK_CMDLINE_ALLOC_LOGGING) -+#include "duk_alloc_logging.h" -+#endif -+#if defined(DUK_CMDLINE_ALLOC_TORTURE) -+#include "duk_alloc_torture.h" -+#endif -+#if defined(DUK_CMDLINE_ALLOC_HYBRID) -+#include "duk_alloc_hybrid.h" -+#endif -+#include "duktape.h" -+ -+#include "duk_cmdline.h" -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+#include "duk_alloc_pool.h" -+#endif -+ -+#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) -+#include "duk_trans_socket.h" -+#endif -+ -+#if defined(DUK_USE_FUZZILLI) -+/* REPRL Pipe file descriptors for quicker fuzzing. */ -+#define REPRL_CRFD 100 -+#define REPRL_CWFD 101 -+#define REPRL_DRFD 102 -+#define REPRL_DWFD 103 -+/* Required includes for coverage tracking. */ -+#include -+#include -+#include -+#include -+#include -+#endif -+ -+#define MEM_LIMIT_NORMAL (128*1024*1024) /* 128 MB */ -+#define MEM_LIMIT_HIGH (2047*1024*1024) /* ~2 GB */ -+#define LINEBUF_SIZE 65536 -+ -+static int main_argc = 0; -+static const char **main_argv = NULL; -+static int interactive_mode = 0; -+static int allow_bytecode = 0; -+#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) -+static int debugger_reattach = 0; -+#endif -+#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) -+static int no_auto_complete = 0; -+#endif -+ -+int duk_cmdline_stack_check(void); -+ -+/* -+ * Misc helpers -+ */ -+ -+static void print_greet_line(void) { -+ printf("((o) Duktape%s %d.%d.%d (%s)\n", -+#if defined(DUK_CMDLINE_LINENOISE) -+ " [linenoise]", -+#else -+ "", -+#endif -+ (int) (DUK_VERSION / 10000), -+ (int) ((DUK_VERSION / 100) % 100), -+ (int) (DUK_VERSION % 100), -+ DUK_GIT_DESCRIBE); -+} -+ -+#if defined(DUK_CMDLINE_RLIMIT) -+static void set_resource_limits(rlim_t mem_limit_value) { -+ int rc; -+ struct rlimit lim; -+ -+ rc = getrlimit(RLIMIT_AS, &lim); -+ if (rc != 0) { -+ fprintf(stderr, "Warning: cannot read RLIMIT_AS\n"); -+ return; -+ } -+ -+ if (lim.rlim_max < mem_limit_value) { -+ fprintf(stderr, "Warning: rlim_max < mem_limit_value (%d < %d)\n", (int) lim.rlim_max, (int) mem_limit_value); -+ return; -+ } -+ -+ lim.rlim_cur = mem_limit_value; -+ lim.rlim_max = mem_limit_value; -+ -+ rc = setrlimit(RLIMIT_AS, &lim); -+ if (rc != 0) { -+ fprintf(stderr, "Warning: setrlimit failed\n"); -+ return; -+ } -+ -+#if 0 -+ fprintf(stderr, "Set RLIMIT_AS to %d\n", (int) mem_limit_value); -+#endif -+} -+#endif /* DUK_CMDLINE_RLIMIT */ -+ -+#if defined(DUK_CMDLINE_SIGNAL) -+static void my_sighandler(int x) { -+ fprintf(stderr, "Got signal %d\n", x); -+ fflush(stderr); -+} -+static void set_sigint_handler(void) { -+ (void) signal(SIGINT, my_sighandler); -+ (void) signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE killing process */ -+} -+#endif /* DUK_CMDLINE_SIGNAL */ -+ -+static void cmdline_fatal_handler(void *udata, const char *msg) { -+ (void) udata; -+ fprintf(stderr, "*** FATAL ERROR: %s\n", msg ? msg : "no message"); -+ fprintf(stderr, "Causing intentional segfault...\n"); -+ fflush(stderr); -+ *((volatile unsigned int *) 0) = (unsigned int) 0xdeadbeefUL; -+ abort(); -+} -+ -+/* Print error to stderr and pop error. */ -+static void print_pop_error(duk_context *ctx, FILE *f) { -+ fprintf(f, "%s\n", duk_safe_to_stacktrace(ctx, -1)); -+ fflush(f); -+ duk_pop(ctx); -+} -+ -+static duk_ret_t wrapped_compile_execute(duk_context *ctx, void *udata) { -+ const char *src_data; -+ duk_size_t src_len; -+ duk_uint_t comp_flags; -+ -+ (void) udata; -+ -+ /* XXX: Here it'd be nice to get some stats for the compilation result -+ * when a suitable command line is given (e.g. code size, constant -+ * count, function count. These are available internally but not through -+ * the public API. -+ */ -+ -+ /* Use duk_compile_lstring_filename() variant which avoids interning -+ * the source code. This only really matters for low memory environments. -+ */ -+ -+ /* [ ... bytecode_filename src_data src_len filename ] */ -+ -+ src_data = (const char *) duk_require_pointer(ctx, -3); -+ src_len = (duk_size_t) duk_require_uint(ctx, -2); -+ -+ if (src_data != NULL && src_len >= 1 && src_data[0] == (char) 0xbf) { -+ /* Bytecode. */ -+ if (allow_bytecode) { -+ void *buf; -+ buf = duk_push_fixed_buffer(ctx, src_len); -+ memcpy(buf, (const void *) src_data, src_len); -+ duk_load_function(ctx); -+ } else { -+ (void) duk_type_error(ctx, "bytecode input rejected (use -b to allow bytecode inputs)"); -+ } -+ } else { -+ /* Source code. */ -+ comp_flags = DUK_COMPILE_SHEBANG; -+ duk_compile_lstring_filename(ctx, comp_flags, src_data, src_len); -+ } -+ -+ /* [ ... bytecode_filename src_data src_len function ] */ -+ -+ /* Optional bytecode dump. */ -+ if (duk_is_string(ctx, -4)) { -+ FILE *f; -+ void *bc_ptr; -+ duk_size_t bc_len; -+ size_t wrote; -+ char fnbuf[256]; -+ const char *filename; -+ -+ duk_dup_top(ctx); -+ duk_dump_function(ctx); -+ bc_ptr = duk_require_buffer_data(ctx, -1, &bc_len); -+ filename = duk_require_string(ctx, -5); -+#if defined(EMSCRIPTEN) -+ if (filename[0] == '/') { -+ snprintf(fnbuf, sizeof(fnbuf), "%s", filename); -+ } else { -+ snprintf(fnbuf, sizeof(fnbuf), "/working/%s", filename); -+ } -+#else -+ snprintf(fnbuf, sizeof(fnbuf), "%s", filename); -+#endif -+ fnbuf[sizeof(fnbuf) - 1] = (char) 0; -+ -+ f = fopen(fnbuf, "wb"); -+ if (!f) { -+ (void) duk_generic_error(ctx, "failed to open bytecode output file"); -+ } -+ wrote = fwrite(bc_ptr, 1, (size_t) bc_len, f); /* XXX: handle partial writes */ -+ (void) fclose(f); -+ if (wrote != bc_len) { -+ (void) duk_generic_error(ctx, "failed to write all bytecode"); -+ } -+ -+ return 0; /* duk_safe_call() cleans up */ -+ } -+ -+#if 0 -+ /* Manual test for bytecode dump/load cycle: dump and load before -+ * execution. Enable manually, then run "make ecmatest" for a -+ * reasonably good coverage of different functions and programs. -+ */ -+ duk_dump_function(ctx); -+ duk_load_function(ctx); -+#endif -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ lowmem_start_exec_timeout(); -+#endif -+ -+ duk_push_global_object(ctx); /* 'this' binding */ -+ duk_call_method(ctx, 0); -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ lowmem_clear_exec_timeout(); -+#endif -+ -+ if (interactive_mode) { -+ /* -+ * In interactive mode, write to stdout so output won't -+ * interleave as easily. -+ * -+ * NOTE: the ToString() coercion may fail in some cases; -+ * for instance, if you evaluate: -+ * -+ * ( {valueOf: function() {return {}}, -+ * toString: function() {return {}}}); -+ * -+ * The error is: -+ * -+ * TypeError: coercion to primitive failed -+ * duk_api.c:1420 -+ * -+ * These are handled now by the caller which also has stack -+ * trace printing support. User code can print out errors -+ * safely using duk_safe_to_string(). -+ */ -+ -+ duk_push_global_stash(ctx); -+ duk_get_prop_string(ctx, -1, "dukFormat"); -+ duk_dup(ctx, -3); -+ duk_call(ctx, 1); /* -> [ ... res stash formatted ] */ -+ -+ fprintf(stdout, "= %s\n", duk_to_string(ctx, -1)); -+ fflush(stdout); -+ } else { -+ /* In non-interactive mode, success results are not written at all. -+ * It is important that the result value is not string coerced, -+ * as the string coercion may cause an error in some cases. -+ */ -+ } -+ -+ return 0; /* duk_safe_call() cleans up */ -+} -+ -+/* -+ * Minimal Linenoise completion support -+ */ -+ -+#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) -+static duk_context *completion_ctx; -+ -+static const char *linenoise_completion_script = -+ "(function linenoiseCompletion(input, addCompletion) {\n" -+ " // Find maximal trailing string which looks like a property\n" -+ " // access. Look up all the components (starting from the global\n" -+ " // object now) except the last; treat the last component as a\n" -+ " // partial name and use it as a filter for possible properties.\n" -+ " var match, propseq, obj, i, partial, names, name, sanity;\n" -+ "\n" -+ " if (!input) { return; }\n" -+ " match = /^.*?((?:\\w+\\.)*\\w*)$/.exec(input);\n" -+ " if (!match || !match[1]) { return; }\n" -+ " var propseq = match[1].split('.');\n" -+ "\n" -+ " obj = Function('return this')();\n" -+ " for (i = 0; i < propseq.length - 1; i++) {\n" -+ " if (obj === void 0 || obj === null) { return; }\n" -+ " obj = obj[propseq[i]];\n" -+ " }\n" -+ " if (obj === void 0 || obj === null) { return; }\n" -+ "\n" -+ " partial = propseq[propseq.length - 1];\n" -+ " sanity = 1000;\n" -+ " while (obj != null) {\n" -+ " if (--sanity < 0) { throw new Error('sanity'); }\n" -+ " names = Object.getOwnPropertyNames(Object(obj));\n" -+ " for (i = 0; i < names.length; i++) {\n" -+ " if (--sanity < 0) { throw new Error('sanity'); }\n" -+ " name = names[i];\n" -+ " if (Number(name) >= 0) { continue; } // ignore array keys\n" -+ " if (name.substring(0, partial.length) !== partial) { continue; }\n" -+ " if (name === partial) { addCompletion(input + '.'); continue; }\n" -+ " addCompletion(input + name.substring(partial.length));\n" -+ " }\n" -+ " obj = Object.getPrototypeOf(Object(obj));\n" -+ " }\n" -+ "})"; -+ -+static const char *linenoise_hints_script = -+ "(function linenoiseHints(input) {\n" -+ " // Similar to completions but different handling for final results.\n" -+ " var match, propseq, obj, i, partial, names, name, res, found, first, sanity;\n" -+ "\n" -+ " if (!input) { return; }\n" -+ " match = /^.*?((?:\\w+\\.)*\\w*)$/.exec(input);\n" -+ " if (!match || !match[1]) { return; }\n" -+ " var propseq = match[1].split('.');\n" -+ "\n" -+ " obj = Function('return this')();\n" -+ " for (i = 0; i < propseq.length - 1; i++) {\n" -+ " if (obj === void 0 || obj === null) { return; }\n" -+ " obj = obj[propseq[i]];\n" -+ " }\n" -+ " if (obj === void 0 || obj === null) { return; }\n" -+ "\n" -+ " partial = propseq[propseq.length - 1];\n" -+ " res = [];\n" -+ " found = Object.create(null); // keys already handled\n" -+ " sanity = 1000;\n" -+ " while (obj != null) {\n" -+ " if (--sanity < 0) { throw new Error('sanity'); }\n" -+ " names = Object.getOwnPropertyNames(Object(obj));\n" -+ " first = true;\n" -+ " for (i = 0; i < names.length; i++) {\n" -+ " if (--sanity < 0) { throw new Error('sanity'); }\n" -+ " name = names[i];\n" -+ " if (Number(name) >= 0) { continue; } // ignore array keys\n" -+ " if (name.substring(0, partial.length) !== partial) { continue; }\n" -+ " if (name === partial) { continue; }\n" -+ " if (found[name]) { continue; }\n" -+ " found[name] = true;\n" -+ " res.push(res.length === 0 ? name.substring(partial.length) : (first ? ' || ' : ' | ') + name);\n" -+ " first = false;\n" -+ " }\n" -+ " obj = Object.getPrototypeOf(Object(obj));\n" -+ " }\n" -+ " return { hints: res.join(''), color: 35, bold: 1 };\n" -+ "})"; -+ -+static duk_ret_t linenoise_add_completion(duk_context *ctx) { -+ linenoiseCompletions *lc; -+ -+ duk_push_current_function(ctx); -+ duk_get_prop_string(ctx, -1, "lc"); -+ lc = duk_require_pointer(ctx, -1); -+ -+ linenoiseAddCompletion(lc, duk_require_string(ctx, 0)); -+ return 0; -+} -+ -+static char *linenoise_hints(const char *buf, int *color, int *bold) { -+ duk_context *ctx; -+ duk_int_t rc; -+ -+ ctx = completion_ctx; -+ if (!ctx) { -+ return NULL; -+ } -+ -+ duk_push_global_stash(ctx); -+ duk_get_prop_string(ctx, -1, "linenoiseHints"); -+ if (!buf) { -+ duk_push_undefined(ctx); -+ } else { -+ duk_push_string(ctx, buf); -+ } -+ -+ rc = duk_pcall(ctx, 1 /*nargs*/); /* [ stash func ] -> [ stash result ] */ -+ if (rc != 0) { -+ const char *res; -+ res = strdup(duk_safe_to_string(ctx, -1)); -+ *color = 31; /* red */ -+ *bold = 1; -+ duk_pop_2(ctx); -+ return (char *) (uintptr_t) res; /* uintptr_t cast to avoid const discard warning. */ -+ } -+ -+ if (duk_is_object(ctx, -1)) { -+ const char *tmp; -+ const char *res = NULL; -+ -+ duk_get_prop_string(ctx, -1, "hints"); -+ tmp = duk_get_string(ctx, -1); -+ if (tmp) { -+ res = strdup(tmp); -+ } -+ duk_pop(ctx); -+ -+ duk_get_prop_string(ctx, -1, "color"); -+ *color = duk_to_int(ctx, -1); -+ duk_pop(ctx); -+ -+ duk_get_prop_string(ctx, -1, "bold"); -+ *bold = duk_to_int(ctx, -1); -+ duk_pop(ctx); -+ -+ duk_pop_2(ctx); -+ return (char *) (uintptr_t) res; /* uintptr_t cast to avoid const discard warning. */ -+ } -+ -+ duk_pop_2(ctx); -+ return NULL; -+} -+ -+static void linenoise_freehints(void *ptr) { -+#if 0 -+ printf("free hint: %p\n", (void *) ptr); -+#endif -+ free(ptr); -+} -+ -+static void linenoise_completion(const char *buf, linenoiseCompletions *lc) { -+ duk_context *ctx; -+ duk_int_t rc; -+ -+ ctx = completion_ctx; -+ if (!ctx) { -+ return; -+ } -+ -+ duk_push_global_stash(ctx); -+ duk_get_prop_string(ctx, -1, "linenoiseCompletion"); -+ -+ if (!buf) { -+ duk_push_undefined(ctx); -+ } else { -+ duk_push_string(ctx, buf); -+ } -+ duk_push_c_function(ctx, linenoise_add_completion, 2 /*nargs*/); -+ duk_push_pointer(ctx, (void *) lc); -+ duk_put_prop_string(ctx, -2, "lc"); -+ -+ rc = duk_pcall(ctx, 2 /*nargs*/); /* [ stash func callback ] -> [ stash result ] */ -+ if (rc != 0) { -+ linenoiseAddCompletion(lc, duk_safe_to_string(ctx, -1)); -+ } -+ duk_pop_2(ctx); -+} -+#endif /* DUK_CMDLINE_LINENOISE_COMPLETION */ -+ -+/* -+ * Execute from file handle etc -+ */ -+ -+static int handle_fh(duk_context *ctx, FILE *f, const char *filename, const char *bytecode_filename) { -+ char *buf = NULL; -+ size_t bufsz; -+ size_t bufoff; -+ size_t got; -+ int rc; -+ int retval = -1; -+ -+ buf = (char *) malloc(1024); -+ if (!buf) { -+ goto error; -+ } -+ bufsz = 1024; -+ bufoff = 0; -+ -+ /* Read until EOF, avoid fseek/stat because it won't work with stdin. */ -+ for (;;) { -+ size_t avail; -+ -+ avail = bufsz - bufoff; -+ if (avail < 1024) { -+ size_t newsz; -+ char *buf_new; -+#if 0 -+ fprintf(stderr, "resizing read buffer: %ld -> %ld\n", (long) bufsz, (long) (bufsz * 2)); -+#endif -+ newsz = bufsz + (bufsz >> 2) + 1024; /* +25% and some extra */ -+ buf_new = (char *) realloc(buf, newsz); -+ if (!buf_new) { -+ goto error; -+ } -+ buf = buf_new; -+ bufsz = newsz; -+ } -+ -+ avail = bufsz - bufoff; -+#if 0 -+ fprintf(stderr, "reading input: buf=%p bufsz=%ld bufoff=%ld avail=%ld\n", -+ (void *) buf, (long) bufsz, (long) bufoff, (long) avail); -+#endif -+ -+ got = fread((void *) (buf + bufoff), (size_t) 1, avail, f); -+#if 0 -+ fprintf(stderr, "got=%ld\n", (long) got); -+#endif -+ if (got == 0) { -+ break; -+ } -+ bufoff += got; -+ -+ /* Emscripten specific: stdin EOF doesn't work as expected. -+ * Instead, when 'emduk' is executed using Node.js, a file -+ * piped to stdin repeats (!). Detect that repeat and cut off -+ * the stdin read. Ensure the loop repeats enough times to -+ * avoid detecting spurious loops. -+ * -+ * This only seems to work for inputs up to 256 bytes long. -+ */ -+#if defined(EMSCRIPTEN) -+ if (bufoff >= 16384) { -+ size_t i, j, nloops; -+ int looped = 0; -+ -+ for (i = 16; i < bufoff / 8; i++) { -+ int ok; -+ -+ nloops = bufoff / i; -+ ok = 1; -+ for (j = 1; j < nloops; j++) { -+ if (memcmp((void *) buf, (void *) (buf + i * j), i) != 0) { -+ ok = 0; -+ break; -+ } -+ } -+ if (ok) { -+ fprintf(stderr, "emscripten workaround: detect looping at index %ld, verified with %ld loops\n", (long) i, (long) (nloops - 1)); -+ bufoff = i; -+ looped = 1; -+ break; -+ } -+ } -+ -+ if (looped) { -+ break; -+ } -+ } -+#endif -+ } -+ -+ duk_push_string(ctx, bytecode_filename); -+ duk_push_pointer(ctx, (void *) buf); -+ duk_push_uint(ctx, (duk_uint_t) bufoff); -+ duk_push_string(ctx, filename); -+ -+ interactive_mode = 0; /* global */ -+ -+ rc = duk_safe_call(ctx, wrapped_compile_execute, NULL /*udata*/, 4 /*nargs*/, 1 /*nret*/); -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ lowmem_clear_exec_timeout(); -+#endif -+ -+ free(buf); -+ buf = NULL; -+ -+ if (rc != DUK_EXEC_SUCCESS) { -+ print_pop_error(ctx, stderr); -+ goto error; -+ } else { -+ duk_pop(ctx); -+ retval = 0; -+ } -+ /* fall thru */ -+ -+ cleanup: -+ if (buf) { -+ free(buf); -+ buf = NULL; -+ } -+ return retval; -+ -+ error: -+ fprintf(stderr, "error in executing file %s\n", filename); -+ fflush(stderr); -+ goto cleanup; -+} -+ -+static int handle_file(duk_context *ctx, const char *filename, const char *bytecode_filename) { -+ FILE *f = NULL; -+ int retval; -+ char fnbuf[256]; -+ -+ /* Example of sending an application specific debugger notification. */ -+ duk_push_string(ctx, "DebuggerHandleFile"); -+ duk_push_string(ctx, filename); -+ duk_debugger_notify(ctx, 2); -+ -+#if defined(EMSCRIPTEN) -+ if (filename[0] == '/') { -+ snprintf(fnbuf, sizeof(fnbuf), "%s", filename); -+ } else { -+ snprintf(fnbuf, sizeof(fnbuf), "/working/%s", filename); -+ } -+#else -+ snprintf(fnbuf, sizeof(fnbuf), "%s", filename); -+#endif -+ fnbuf[sizeof(fnbuf) - 1] = (char) 0; -+ -+ f = fopen(fnbuf, "rb"); -+ if (!f) { -+ fprintf(stderr, "failed to open source file: %s\n", filename); -+ fflush(stderr); -+ goto error; -+ } -+ -+ retval = handle_fh(ctx, f, filename, bytecode_filename); -+ -+ fclose(f); -+ return retval; -+ -+ error: -+ return -1; -+} -+ -+static int handle_eval(duk_context *ctx, const char *code) { -+ int rc; -+ int retval = -1; -+ union { -+ void *ptr; -+ const void *constptr; -+ } u; -+ -+ u.constptr = code; /* Lose 'const' without warning. */ -+ duk_push_pointer(ctx, u.ptr); -+ duk_push_uint(ctx, (duk_uint_t) strlen(code)); -+ duk_push_string(ctx, "eval"); -+ -+ interactive_mode = 0; /* global */ -+ -+ rc = duk_safe_call(ctx, wrapped_compile_execute, NULL /*udata*/, 3 /*nargs*/, 1 /*nret*/); -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ lowmem_clear_exec_timeout(); -+#endif -+ -+ if (rc != DUK_EXEC_SUCCESS) { -+ print_pop_error(ctx, stderr); -+ } else { -+ duk_pop(ctx); -+ retval = 0; -+ } -+ -+ return retval; -+} -+ -+#if defined(DUK_CMDLINE_LINENOISE) -+static int handle_interactive(duk_context *ctx) { -+ const char *prompt = "duk> "; -+ char *buffer = NULL; -+ int retval = 0; -+ int rc; -+ -+ linenoiseSetMultiLine(1); -+ linenoiseHistorySetMaxLen(64); -+#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) -+ if (!no_auto_complete) { -+ linenoiseSetCompletionCallback(linenoise_completion); -+ linenoiseSetHintsCallback(linenoise_hints); -+ linenoiseSetFreeHintsCallback(linenoise_freehints); -+ duk_push_global_stash(ctx); -+ duk_eval_string(ctx, linenoise_completion_script); -+ duk_put_prop_string(ctx, -2, "linenoiseCompletion"); -+ duk_eval_string(ctx, linenoise_hints_script); -+ duk_put_prop_string(ctx, -2, "linenoiseHints"); -+ duk_pop(ctx); -+ } -+#endif -+ -+ for (;;) { -+ if (buffer) { -+ linenoiseFree(buffer); -+ buffer = NULL; -+ } -+ -+#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) -+ completion_ctx = ctx; -+#endif -+ buffer = linenoise(prompt); -+#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) -+ completion_ctx = NULL; -+#endif -+ -+ if (!buffer) { -+ break; -+ } -+ -+ if (buffer && buffer[0] != (char) 0) { -+ linenoiseHistoryAdd(buffer); -+ } -+ -+ duk_push_pointer(ctx, (void *) buffer); -+ duk_push_uint(ctx, (duk_uint_t) strlen(buffer)); -+ duk_push_string(ctx, "input"); -+ -+ interactive_mode = 1; /* global */ -+ -+ rc = duk_safe_call(ctx, wrapped_compile_execute, NULL /*udata*/, 3 /*nargs*/, 1 /*nret*/); -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ lowmem_clear_exec_timeout(); -+#endif -+ -+ if (buffer) { -+ linenoiseFree(buffer); -+ buffer = NULL; -+ } -+ -+ if (rc != DUK_EXEC_SUCCESS) { -+ /* in interactive mode, write to stdout */ -+ print_pop_error(ctx, stdout); -+ retval = -1; /* an error 'taints' the execution */ -+ } else { -+ duk_pop(ctx); -+ } -+ } -+ -+ if (buffer) { -+ linenoiseFree(buffer); -+ buffer = NULL; -+ } -+ -+ return retval; -+} -+#else /* DUK_CMDLINE_LINENOISE */ -+static int handle_interactive(duk_context *ctx) { -+ const char *prompt = "duk> "; -+ char *buffer = NULL; -+ int retval = 0; -+ int rc; -+ int got_eof = 0; -+ -+ buffer = (char *) malloc(LINEBUF_SIZE); -+ if (!buffer) { -+ fprintf(stderr, "failed to allocated a line buffer\n"); -+ fflush(stderr); -+ retval = -1; -+ goto done; -+ } -+ -+ while (!got_eof) { -+ size_t idx = 0; -+ -+ fwrite(prompt, 1, strlen(prompt), stdout); -+ fflush(stdout); -+ -+ for (;;) { -+ int c = fgetc(stdin); -+ if (c == EOF) { -+ got_eof = 1; -+ break; -+ } else if (c == '\n') { -+ break; -+ } else if (idx >= LINEBUF_SIZE) { -+ fprintf(stderr, "line too long\n"); -+ fflush(stderr); -+ retval = -1; -+ goto done; -+ } else { -+ buffer[idx++] = (char) c; -+ } -+ } -+ -+ duk_push_pointer(ctx, (void *) buffer); -+ duk_push_uint(ctx, (duk_uint_t) idx); -+ duk_push_string(ctx, "input"); -+ -+ interactive_mode = 1; /* global */ -+ -+ rc = duk_safe_call(ctx, wrapped_compile_execute, NULL /*udata*/, 3 /*nargs*/, 1 /*nret*/); -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ lowmem_clear_exec_timeout(); -+#endif -+ -+ if (rc != DUK_EXEC_SUCCESS) { -+ /* in interactive mode, write to stdout */ -+ print_pop_error(ctx, stdout); -+ retval = -1; /* an error 'taints' the execution */ -+ } else { -+ duk_pop(ctx); -+ } -+ } -+ -+ done: -+ if (buffer) { -+ free(buffer); -+ buffer = NULL; -+ } -+ -+ return retval; -+} -+#endif /* DUK_CMDLINE_LINENOISE */ -+ -+/* -+ * Simple file read/write bindings -+ */ -+ -+#if defined(DUK_CMDLINE_FILEIO) -+static duk_ret_t fileio_read_file(duk_context *ctx) { -+ const char *fn; -+ char *buf; -+ size_t len; -+ size_t off; -+ int rc; -+ FILE *f; -+ -+ fn = duk_require_string(ctx, 0); -+ f = fopen(fn, "rb"); -+ if (!f) { -+ (void) duk_type_error(ctx, "cannot open file %s for reading, errno %ld: %s", -+ fn, (long) errno, strerror(errno)); -+ } -+ -+ rc = fseek(f, 0, SEEK_END); -+ if (rc < 0) { -+ (void) fclose(f); -+ (void) duk_type_error(ctx, "fseek() failed for %s, errno %ld: %s", -+ fn, (long) errno, strerror(errno)); -+ } -+ len = (size_t) ftell(f); -+ rc = fseek(f, 0, SEEK_SET); -+ if (rc < 0) { -+ (void) fclose(f); -+ (void) duk_type_error(ctx, "fseek() failed for %s, errno %ld: %s", -+ fn, (long) errno, strerror(errno)); -+ } -+ -+ buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) len); -+ for (off = 0; off < len;) { -+ size_t got; -+ got = fread((void *) (buf + off), 1, len - off, f); -+ if (ferror(f)) { -+ (void) fclose(f); -+ (void) duk_type_error(ctx, "error while reading %s", fn); -+ } -+ if (got == 0) { -+ if (feof(f)) { -+ break; -+ } else { -+ (void) fclose(f); -+ (void) duk_type_error(ctx, "error while reading %s", fn); -+ } -+ } -+ off += got; -+ } -+ -+ if (f) { -+ (void) fclose(f); -+ } -+ -+ return 1; -+} -+ -+static duk_ret_t fileio_write_file(duk_context *ctx) { -+ const char *fn; -+ const char *buf; -+ size_t len; -+ size_t off; -+ FILE *f; -+ -+ fn = duk_require_string(ctx, 0); -+ f = fopen(fn, "wb"); -+ if (!f) { -+ (void) duk_type_error(ctx, "cannot open file %s for writing, errno %ld: %s", -+ fn, (long) errno, strerror(errno)); -+ } -+ -+ len = 0; -+ buf = (char *) duk_require_buffer_data(ctx, 1, &len); -+ for (off = 0; off < len;) { -+ size_t got; -+ got = fwrite((const void *) (buf + off), 1, len - off, f); -+ if (ferror(f)) { -+ (void) fclose(f); -+ (void) duk_type_error(ctx, "error while writing %s", fn); -+ } -+ if (got == 0) { -+ (void) fclose(f); -+ (void) duk_type_error(ctx, "error while writing %s", fn); -+ } -+ off += got; -+ } -+ -+ if (f) { -+ (void) fclose(f); -+ } -+ -+ return 0; -+} -+ -+static duk_ret_t sys_execute(duk_context *ctx) { -+ const char *command = duk_require_string(ctx, 0); -+ int rc; -+ -+ rc = system(command); -+ if (rc != 0) { -+ duk_push_error_object(ctx, DUK_ERR_TYPE_ERROR, "system() failed with code %d", rc); -+ duk_push_int(ctx, rc); -+ duk_put_prop_string(ctx, -2, "exitCode"); -+ return duk_throw(ctx); -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(DUK_USE_FUZZILLI) -+/* Custom builtin for Fuzzilli, used to ensure the fuzzer is properly catching -+ * crashes and assert failures. -+ */ -+static duk_ret_t fuzzilli(duk_context *ctx) { -+ const char *first_arg = duk_require_string(ctx, 0); -+ -+ if (strcmp(first_arg, "FUZZILLI_CRASH") == 0) { -+ duk_int_t second_arg = duk_get_int(ctx, 1); -+ switch (second_arg) { -+ case 0: -+ *((duk_int_t *)0x41414141) = 0x1337; /* intentionally segfault */ -+ break; -+ default: -+ duk_assert_wrapper(0); /* Intentionally fail assertion */ -+ break; -+ } -+ } else if (strcmp(first_arg, "FUZZILLI_PRINT") == 0) { -+ const char *string = duk_require_string(ctx, 1); -+ -+ FILE *fzliout = fdopen(REPRL_DWFD, "w"); -+ if (!fzliout) { -+ fprintf(stderr, "Fuzzer output channel not available, printing to stdout instead\n"); -+ fzliout = stdout; -+ } -+ fprintf(fzliout, "%s\n", string); -+ fflush(fzliout); -+ } -+ -+ return 0; -+} -+#endif /* DUK_USE_FUZZILLI */ -+ -+/* -+ * String.fromBufferRaw() -+ */ -+ -+static duk_ret_t string_frombufferraw(duk_context *ctx) { -+ duk_buffer_to_string(ctx, 0); -+ return 1; -+} -+ -+/* -+ * Duktape heap lifecycle -+ */ -+ -+#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) -+static duk_idx_t debugger_request(duk_context *ctx, void *udata, duk_idx_t nvalues) { -+ const char *cmd; -+ int i; -+ -+ (void) udata; -+ -+ if (nvalues < 1) { -+ duk_push_string(ctx, "missing AppRequest argument(s)"); -+ return -1; -+ } -+ -+ cmd = duk_get_string(ctx, -nvalues + 0); -+ -+ if (cmd && strcmp(cmd, "CommandLine") == 0) { -+ if (!duk_check_stack(ctx, main_argc)) { -+ /* Callback should avoid errors for now, so use -+ * duk_check_stack() rather than duk_require_stack(). -+ */ -+ duk_push_string(ctx, "failed to extend stack"); -+ return -1; -+ } -+ for (i = 0; i < main_argc; i++) { -+ duk_push_string(ctx, main_argv[i]); -+ } -+ return main_argc; -+ } -+ duk_push_sprintf(ctx, "command not supported"); -+ return -1; -+} -+ -+static void debugger_detached(duk_context *ctx, void *udata) { -+ fprintf(stderr, "Debugger detached, udata: %p\n", (void *) udata); -+ fflush(stderr); -+ -+ /* Ensure socket is closed even when detach is initiated by Duktape -+ * rather than debug client. -+ */ -+ duk_trans_socket_finish(); -+ -+ if (debugger_reattach) { -+ /* For automatic reattach testing. */ -+ duk_trans_socket_init(); -+ duk_trans_socket_waitconn(); -+ fprintf(stderr, "Debugger reconnected, call duk_debugger_attach()\n"); -+ fflush(stderr); -+#if 0 -+ /* This is not necessary but should be harmless. */ -+ duk_debugger_detach(ctx); -+#endif -+ duk_debugger_attach(ctx, -+ duk_trans_socket_read_cb, -+ duk_trans_socket_write_cb, -+ duk_trans_socket_peek_cb, -+ duk_trans_socket_read_flush_cb, -+ duk_trans_socket_write_flush_cb, -+ debugger_request, -+ debugger_detached, -+ NULL); -+ } -+} -+#endif -+ -+#define ALLOC_DEFAULT 0 -+#define ALLOC_LOGGING 1 -+#define ALLOC_TORTURE 2 -+#define ALLOC_HYBRID 3 -+#define ALLOC_LOWMEM 4 -+ -+static duk_context *create_duktape_heap(int alloc_provider, int debugger, int lowmem_log) { -+ duk_context *ctx; -+#if defined(DUK_CMDLINE_FILEIO) -+ int i; -+#endif -+ -+ (void) lowmem_log; /* suppress warning */ -+ -+ ctx = NULL; -+ if (!ctx && alloc_provider == ALLOC_LOGGING) { -+#if defined(DUK_CMDLINE_ALLOC_LOGGING) -+ ctx = duk_create_heap(duk_alloc_logging, -+ duk_realloc_logging, -+ duk_free_logging, -+ (void *) 0xdeadbeef, -+ cmdline_fatal_handler); -+#else -+ fprintf(stderr, "Warning: option --alloc-logging ignored, no logging allocator support\n"); -+ fflush(stderr); -+#endif -+ } -+ if (!ctx && alloc_provider == ALLOC_TORTURE) { -+#if defined(DUK_CMDLINE_ALLOC_TORTURE) -+ ctx = duk_create_heap(duk_alloc_torture, -+ duk_realloc_torture, -+ duk_free_torture, -+ (void *) 0xdeadbeef, -+ cmdline_fatal_handler); -+#else -+ fprintf(stderr, "Warning: option --alloc-torture ignored, no torture allocator support\n"); -+ fflush(stderr); -+#endif -+ } -+ if (!ctx && alloc_provider == ALLOC_HYBRID) { -+#if defined(DUK_CMDLINE_ALLOC_HYBRID) -+ void *udata = duk_alloc_hybrid_init(); -+ if (!udata) { -+ fprintf(stderr, "Failed to init hybrid allocator\n"); -+ fflush(stderr); -+ } else { -+ ctx = duk_create_heap(duk_alloc_hybrid, -+ duk_realloc_hybrid, -+ duk_free_hybrid, -+ udata, -+ cmdline_fatal_handler); -+ } -+#else -+ fprintf(stderr, "Warning: option --alloc-hybrid ignored, no hybrid allocator support\n"); -+ fflush(stderr); -+#endif -+ } -+ if (!ctx && alloc_provider == ALLOC_LOWMEM) { -+#if defined(DUK_CMDLINE_LOWMEM) -+ lowmem_init(); -+ -+ ctx = duk_create_heap( -+ lowmem_log ? lowmem_alloc_wrapped : duk_alloc_pool, -+ lowmem_log ? lowmem_realloc_wrapped : duk_realloc_pool, -+ lowmem_log ? lowmem_free_wrapped : duk_free_pool, -+ (void *) lowmem_pool_ptr, -+ cmdline_fatal_handler); -+#else -+ fprintf(stderr, "Warning: option --alloc-ajsheap ignored, no ajsheap allocator support\n"); -+ fflush(stderr); -+#endif -+ } -+ if (!ctx && alloc_provider == ALLOC_DEFAULT) { -+ ctx = duk_create_heap(NULL, NULL, NULL, NULL, cmdline_fatal_handler); -+ } -+ -+ if (!ctx) { -+ fprintf(stderr, "Failed to create Duktape heap\n"); -+ fflush(stderr); -+ exit(1); -+ } -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ if (alloc_provider == ALLOC_LOWMEM) { -+ fprintf(stderr, "*** pool dump after heap creation ***\n"); -+ lowmem_dump(); -+ } -+#endif -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ if (alloc_provider == ALLOC_LOWMEM) { -+ lowmem_register(ctx); -+ } -+#endif -+ -+ /* Register print() and alert() (removed in Duktape 2.x). */ -+#if defined(DUK_CMDLINE_PRINTALERT_SUPPORT) -+ duk_print_alert_init(ctx, 0 /*flags*/); -+#endif -+ -+ /* Register String.fromBufferRaw() which does a 1:1 buffer-to-string -+ * coercion needed by testcases. String.fromBufferRaw() is -not- a -+ * default built-in! For stripped builds the 'String' built-in -+ * doesn't exist and we create it here; for ROM builds it may be -+ * present but unwritable (which is ignored). -+ */ -+ duk_eval_string(ctx, -+ "(function(v){" -+ "if (typeof String === 'undefined') { String = {}; }" -+ "Object.defineProperty(String, 'fromBufferRaw', {value:v, configurable:true});" -+ "})"); -+ duk_push_c_function(ctx, string_frombufferraw, 1 /*nargs*/); -+ (void) duk_pcall(ctx, 1); -+ duk_pop(ctx); -+ -+ /* Register console object. */ -+#if defined(DUK_CMDLINE_CONSOLE_SUPPORT) -+ duk_console_init(ctx, DUK_CONSOLE_FLUSH /*flags*/); -+#endif -+ -+ /* Register Duktape.Logger (removed in Duktape 2.x). */ -+#if defined(DUK_CMDLINE_LOGGING_SUPPORT) -+ duk_logging_init(ctx, 0 /*flags*/); -+#endif -+ -+ /* Register require() (removed in Duktape 2.x). */ -+#if defined(DUK_CMDLINE_MODULE_SUPPORT) -+ duk_module_duktape_init(ctx); -+#endif -+ -+ /* Trivial file I/O bindings, sysExecute(), and sysArgv for testing. */ -+#if defined(DUK_CMDLINE_FILEIO) -+ duk_push_c_function(ctx, fileio_read_file, 1 /*nargs*/); -+ duk_put_global_string(ctx, "readFile"); -+ duk_push_c_function(ctx, fileio_write_file, 2 /*nargs*/); -+ duk_put_global_string(ctx, "writeFile"); -+ duk_push_c_function(ctx, sys_execute, 1 /*nargs*/); -+ duk_put_global_string(ctx, "sysExecute"); -+ duk_push_array(ctx); -+ for (i = 0; i < main_argc; i++) { -+ duk_push_string(ctx, main_argv[i]); -+ duk_put_prop_index(ctx, -2, (duk_uarridx_t) i); -+ } -+ duk_put_global_string(ctx, "sysArgv"); /* raw argv */ -+#endif -+ -+ /* Stash a formatting function for evaluation results. */ -+ duk_push_global_stash(ctx); -+ duk_eval_string(ctx, -+ "(function (E) {" -+ "return function format(v){" -+ "try{" -+ "return E('jx',v);" -+ "}catch(e){" -+ "return ''+v;" -+ "}" -+ "};" -+ "})(Duktape.enc)"); -+ duk_put_prop_string(ctx, -2, "dukFormat"); -+ duk_pop(ctx); -+ -+ if (debugger) { -+#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) -+ fprintf(stderr, "Debugger enabled, create socket and wait for connection\n"); -+ fflush(stderr); -+ duk_trans_socket_init(); -+ duk_trans_socket_waitconn(); -+ fprintf(stderr, "Debugger connected, call duk_debugger_attach() and then execute requested file(s)/eval\n"); -+ fflush(stderr); -+ duk_debugger_attach(ctx, -+ duk_trans_socket_read_cb, -+ duk_trans_socket_write_cb, -+ duk_trans_socket_peek_cb, -+ duk_trans_socket_read_flush_cb, -+ duk_trans_socket_write_flush_cb, -+ debugger_request, -+ debugger_detached, -+ NULL); -+#else -+ fprintf(stderr, "Warning: option --debugger ignored, no debugger support\n"); -+ fflush(stderr); -+#endif -+ } -+ -+#if 0 -+ /* Manual test for duk_debugger_cooperate() */ -+ { -+ for (i = 0; i < 60; i++) { -+ printf("cooperate: %d\n", i); -+ usleep(1000000); -+ duk_debugger_cooperate(ctx); -+ } -+ } -+#endif -+ -+#if defined(DUK_USE_FUZZILLI) -+ /* Add the custom function for Fuzzilli integration. */ -+ -+ duk_push_c_function(ctx, fuzzilli, 2 /*nargs*/); -+ duk_put_global_string(ctx, "fuzzilli"); -+#endif /* DUK_USE_FUZZILLI */ -+ -+ return ctx; -+} -+ -+static void destroy_duktape_heap(duk_context *ctx, int alloc_provider) { -+ (void) alloc_provider; -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ if (alloc_provider == ALLOC_LOWMEM) { -+ fprintf(stderr, "*** pool dump before duk_destroy_heap(), before forced gc ***\n"); -+ lowmem_dump(); -+ -+ duk_gc(ctx, 0); -+ -+ fprintf(stderr, "*** pool dump before duk_destroy_heap(), after forced gc ***\n"); -+ lowmem_dump(); -+ } -+#endif -+ -+ if (ctx) { -+ duk_destroy_heap(ctx); -+ } -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ if (alloc_provider == ALLOC_LOWMEM) { -+ fprintf(stderr, "*** pool dump after duk_destroy_heap() (should have zero allocs) ***\n"); -+ lowmem_dump(); -+ } -+ lowmem_free(); -+#endif -+} -+ -+#if defined(DUK_USE_FUZZILLI) -+/* Enables coverage tracking for fuzzing. */ -+ -+void __sanitizer_cov_reset_edgeguards(void); -+ -+#define SHM_SIZE 0x100000 -+#define MAX_EDGES ((SHM_SIZE - 4) * 8) -+ -+#define CHECK(cond) if (!(cond)) { fprintf(stderr, "\"" #cond "\" failed\n"); _exit(-1); } -+ -+struct shmem_data { -+ duk_uint32_t num_edges; -+ unsigned char edges[]; -+}; -+ -+struct shmem_data *__shmem; -+duk_uint32_t *__edges_start, *__edges_stop; -+ -+void __sanitizer_cov_reset_edgeguards(void) { -+ duk_uint64_t N = 0; -+ duk_uint32_t *x; -+ for (x = __edges_start; x < __edges_stop && N < MAX_EDGES; x++) { -+ *x = ++N; -+ } -+} -+ -+ -+void __sanitizer_cov_trace_pc_guard_init(duk_uint32_t *start, duk_uint32_t *stop) { -+ /* Avoid duplicate initialization. */ -+ if (start == stop || *start) { -+ return; -+ } -+ -+ if (__edges_start != NULL || __edges_stop != NULL) { -+ fprintf(stderr, "Coverage instrumentation is only supported for a single module\n"); -+ _exit(-1); -+ } -+ -+ __edges_start = start; -+ __edges_stop = stop; -+ -+ /* Map the shared memory region. */ -+ const char *shm_key = getenv("SHM_ID"); -+ if (!shm_key) { -+ puts("[COV] no shared memory bitmap available, skipping"); -+ __shmem = (struct shmem_data *) malloc(SHM_SIZE); -+ } else { -+ int fd = shm_open(shm_key, O_RDWR, S_IREAD | S_IWRITE); -+ if (fd <= -1) { -+ fprintf(stderr, "Failed to open shared memory region: %s\n", strerror(errno)); -+ _exit(-1); -+ } -+ -+ __shmem = (struct shmem_data *) mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -+ if (__shmem == MAP_FAILED) { -+ fprintf(stderr, "Failed to mmap shared memory region\n"); -+ _exit(-1); -+ } -+ } -+ -+ __sanitizer_cov_reset_edgeguards(); -+ -+ __shmem->num_edges = stop - start; -+ printf("[COV] edge counters initialized. Shared memory: %s with %u edges\n", shm_key, __shmem->num_edges); -+} -+ -+void __sanitizer_cov_trace_pc_guard(duk_uint32_t *guard) { -+ /* There's a small race condition here: if this function executes in two threads for the same -+ * edge at the same time, the first thread might disable the edge (by setting the guard to zero) -+ * before the second thread fetches the guard value (and thus the index). However, our -+ * instrumentation ignores the first edge (see libcoverage.c) and so the race is unproblematic. -+ */ -+ duk_uint32_t index = *guard; -+ -+ /* If this function is called before coverage instrumentation is properly initialized we want -+ * to return early. -+ */ -+ if (!index) { -+ return; -+ } -+ -+ __shmem->edges[index / 8] |= 1 << (index % 8); -+ *guard = 0; -+} -+#endif /* DUK_USE_FUZZILLI */ -+ -+/* -+ * Main -+ */ -+ -+int main(int argc, const char *argv[]) { -+ duk_context *ctx = NULL; -+ int retval = 0; -+ int have_files = 0; -+ int have_eval = 0; -+ int interactive = 0; -+ int memlimit_high = 1; -+ int alloc_provider = ALLOC_DEFAULT; -+ int lowmem_log = 0; -+ int debugger = 0; -+ int recreate_heap = 0; -+ int no_heap_destroy = 0; -+ int verbose = 0; -+ int run_stdin = 0; -+ const char *compile_filename = NULL; -+ int i; -+#if defined(DUK_USE_FUZZILLI) -+ int reprl_mode = 0; -+#endif /* DUK_USE_FUZZILLI */ -+ -+ main_argc = argc; -+ main_argv = (const char **) argv; -+ -+#if defined(EMSCRIPTEN) -+ /* Try to use NODEFS to provide access to local files. Mount the -+ * CWD as /working, and then prepend "/working/" to relative native -+ * paths in file calls to get something that works reasonably for -+ * relative paths. Emscripten doesn't support replacing virtual -+ * "/" with host "/" (the default MEMFS at "/" can't be unmounted) -+ * but we can mount "/tmp" as host "/tmp" to allow testcase runs. -+ * -+ * https://kripken.github.io/emscripten-site/docs/api_reference/Filesystem-API.html#filesystem-api-nodefs -+ * https://github.com/kripken/emscripten/blob/master/tests/fs/test_nodefs_rw.c -+ */ -+ EM_ASM( -+ /* At the moment it's not possible to replace the default MEMFS mounted at '/': -+ * https://github.com/kripken/emscripten/issues/2040 -+ * https://github.com/kripken/emscripten/blob/incoming/src/library_fs.js#L1341-L1358 -+ */ -+ /* -+ try { -+ FS.unmount("/"); -+ } catch (e) { -+ console.log("Failed to unmount default '/' MEMFS mount: " + e); -+ } -+ */ -+ try { -+ FS.mkdir("/working"); -+ FS.mount(NODEFS, { root: "." }, "/working"); -+ } catch (e) { -+ console.log("Failed to mount NODEFS /working: " + e); -+ } -+ /* A virtual '/tmp' exists by default: -+ * https://gist.github.com/evanw/e6be28094f34451bd5bd#file-temp-js-L3806-L3809 -+ */ -+ /* -+ try { -+ FS.mkdir("/tmp"); -+ } catch (e) { -+ console.log("Failed to create virtual /tmp: " + e); -+ } -+ */ -+ try { -+ FS.mount(NODEFS, { root: "/tmp" }, "/tmp"); -+ } catch (e) { -+ console.log("Failed to mount NODEFS /tmp: " + e); -+ } -+ ); -+#endif /* EMSCRIPTEN */ -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ alloc_provider = ALLOC_LOWMEM; -+#endif -+ (void) lowmem_log; -+ -+ /* -+ * Signal handling setup -+ */ -+ -+#if defined(DUK_CMDLINE_SIGNAL) -+ set_sigint_handler(); -+ -+ /* This is useful at the global level; libraries should avoid SIGPIPE though */ -+ /*signal(SIGPIPE, SIG_IGN);*/ -+#endif -+ -+ /* -+ * Parse options -+ */ -+ -+ for (i = 1; i < argc; i++) { -+ const char *arg = argv[i]; -+ if (!arg) { -+ goto usage; -+ } else if (strcmp(arg, "--") == 0) { -+ /* Ignore anything after '--'. */ -+ break; -+ } else if (strcmp(arg, "--restrict-memory") == 0) { -+ memlimit_high = 0; -+ } else if (strcmp(arg, "-i") == 0) { -+ interactive = 1; -+ } else if (strcmp(arg, "-b") == 0) { -+ allow_bytecode = 1; -+ } else if (strcmp(arg, "-c") == 0) { -+ if (i == argc - 1) { -+ goto usage; -+ } -+ i++; -+ compile_filename = argv[i]; -+ } else if (strcmp(arg, "-e") == 0) { -+ have_eval = 1; -+ if (i == argc - 1) { -+ goto usage; -+ } -+ i++; /* skip code */ -+ } else if (strcmp(arg, "--alloc-default") == 0) { -+ alloc_provider = ALLOC_DEFAULT; -+ } else if (strcmp(arg, "--alloc-logging") == 0) { -+ alloc_provider = ALLOC_LOGGING; -+ } else if (strcmp(arg, "--alloc-torture") == 0) { -+ alloc_provider = ALLOC_TORTURE; -+ } else if (strcmp(arg, "--alloc-hybrid") == 0) { -+ alloc_provider = ALLOC_HYBRID; -+ } else if (strcmp(arg, "--alloc-lowmem") == 0) { -+ alloc_provider = ALLOC_LOWMEM; -+ } else if (strcmp(arg, "--lowmem-log") == 0) { -+ lowmem_log = 1; -+ } else if (strcmp(arg, "--debugger") == 0) { -+ debugger = 1; -+#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) -+ } else if (strcmp(arg, "--reattach") == 0) { -+ debugger_reattach = 1; -+#endif -+#if defined(DUK_USE_FUZZILLI) -+ } else if (strcmp(arg, "--reprl") == 0) { -+ reprl_mode = 1; -+#endif -+ } else if (strcmp(arg, "--recreate-heap") == 0) { -+ recreate_heap = 1; -+ } else if (strcmp(arg, "--no-heap-destroy") == 0) { -+ no_heap_destroy = 1; -+ } else if (strcmp(arg, "--no-auto-complete") == 0) { -+#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) -+ no_auto_complete = 1; -+#endif -+ } else if (strcmp(arg, "--verbose") == 0) { -+ verbose = 1; -+ } else if (strcmp(arg, "--run-stdin") == 0) { -+ run_stdin = 1; -+ } else if (strlen(arg) >= 1 && arg[0] == '-') { -+ goto usage; -+ } else { -+ have_files = 1; -+ } -+ } -+ if (!have_files && !have_eval && !run_stdin) { -+ interactive = 1; -+ } -+ -+ /* -+ * Memory limit -+ */ -+ -+#if defined(DUK_CMDLINE_RLIMIT) -+ set_resource_limits(memlimit_high ? MEM_LIMIT_HIGH : MEM_LIMIT_NORMAL); -+#else -+ if (memlimit_high == 0) { -+ fprintf(stderr, "Warning: option --restrict-memory ignored, no rlimit support\n"); -+ fflush(stderr); -+ } -+#endif -+ -+ /* -+ * Create heap -+ */ -+ -+ ctx = create_duktape_heap(alloc_provider, debugger, lowmem_log); -+ -+ /* -+ * Execute any argument file(s) -+ */ -+ -+ for (i = 1; i < argc; i++) { -+ const char *arg = argv[i]; -+ if (!arg) { -+ continue; -+ } else if (strcmp(arg, "--") == 0) { -+ /* Ignore anything after '--'. */ -+ break; -+ } else if (strlen(arg) == 2 && strcmp(arg, "-e") == 0) { -+ /* Here we know the eval arg exists but check anyway */ -+ if (i == argc - 1) { -+ retval = 1; -+ goto cleanup; -+ } -+ if (handle_eval(ctx, argv[i + 1]) != 0) { -+ retval = 1; -+ goto cleanup; -+ } -+ i++; /* skip code */ -+ continue; -+ } else if (strlen(arg) == 2 && strcmp(arg, "-c") == 0) { -+ i++; /* skip filename */ -+ continue; -+ } else if (strlen(arg) >= 1 && arg[0] == '-') { -+ continue; -+ } -+ -+ if (verbose) { -+ fprintf(stderr, "*** Executing file: %s\n", arg); -+ fflush(stderr); -+ } -+ -+ if (handle_file(ctx, arg, compile_filename) != 0) { -+ retval = 1; -+ goto cleanup; -+ } -+ -+ if (recreate_heap) { -+ if (verbose) { -+ fprintf(stderr, "*** Recreating heap...\n"); -+ fflush(stderr); -+ } -+ -+ destroy_duktape_heap(ctx, alloc_provider); -+ ctx = create_duktape_heap(alloc_provider, debugger, lowmem_log); -+ } -+ } -+ -+#if defined(DUK_USE_FUZZILLI) -+ /* Run the fuzzilli run-eval-print-repeat loop, and exit at the end. */ -+ if (reprl_mode) { -+ /* REPRL: let parent know we are ready */ -+ char helo[4] = "HELO"; -+ if (write(REPRL_CWFD, helo, 4) != 4 || -+ read(REPRL_CRFD, helo, 4) != 4) { -+ reprl_mode = 0; -+ } -+ -+ if (memcmp(helo, "HELO", 4) != 0) { -+ fprintf(stderr, "Invalid response from parent\n"); -+ _exit(-1); -+ } -+ -+ while (reprl_mode) { -+ unsigned int action = 0; -+ duk_size_t script_size; -+ char static_buff[4096]; -+ char *buffer; -+ char *ptr; -+ duk_size_t remaining; -+ duk_int_t rc; -+ -+ duk_int64_t nread = read(REPRL_CRFD, &action, 4); -+ if (nread != 4 || action != 'cexe') { -+ fprintf(stderr, "Unknown action: %u\n", action); -+ duk_assert_wrapper(0); -+ _exit(-1); -+ } -+ -+ duk_assert_wrapper(read(REPRL_CRFD, &script_size, 8) == 8); -+ /* In practice, we're never going to get to 4k long input scripts (21 core days got to ~80 bytes). */ -+ if (script_size > 4095) { -+ buffer = (char *) malloc((sizeof(char) * (script_size + 1))); -+ } else { -+ buffer = static_buff; -+ } -+ -+ ptr = buffer; -+ remaining = script_size; -+ while (remaining > 0) { -+ duk_int64_t rv = read(REPRL_DRFD, ptr, remaining); -+ duk_assert_wrapper(rv >= 0); -+ remaining -= rv; -+ ptr += rv; -+ } -+ buffer[script_size] = 0; -+ -+ /* Actually execute. */ -+ duk_push_string(ctx, buffer); -+ rc = duk_peval(ctx); -+ -+ /* Return result to parent. */ -+ rc <<= 8; -+ duk_assert_wrapper(write(REPRL_CWFD, &rc, 4) == 4); -+ -+ /* Clean up this round. */ -+ if (script_size > 4095) { -+ free(buffer); -+ } -+ duk_destroy_heap(ctx); -+ ctx = create_duktape_heap(alloc_provider, debugger, lowmem_log); -+ __sanitizer_cov_reset_edgeguards(); -+ } -+ return 0; -+ } /* reprl_mode */ -+#endif -+ -+ if (run_stdin) { -+ /* Running stdin like a full file (reading all lines before -+ * compiling) is useful with emduk: -+ * cat test.js | ./emduk --run-stdin -+ */ -+ if (handle_fh(ctx, stdin, "stdin", compile_filename) != 0) { -+ retval = 1; -+ goto cleanup; -+ } -+ -+ if (recreate_heap) { -+ if (verbose) { -+ fprintf(stderr, "*** Recreating heap...\n"); -+ fflush(stderr); -+ } -+ -+ destroy_duktape_heap(ctx, alloc_provider); -+ ctx = create_duktape_heap(alloc_provider, debugger, lowmem_log); -+ } -+ } -+ -+ /* -+ * Enter interactive mode if options indicate it -+ */ -+ -+ if (interactive) { -+ print_greet_line(); -+ if (handle_interactive(ctx) != 0) { -+ retval = 1; -+ goto cleanup; -+ } -+ } -+ -+ /* -+ * Cleanup and exit -+ */ -+ -+ cleanup: -+ if (interactive) { -+ fprintf(stderr, "Cleaning up...\n"); -+ fflush(stderr); -+ } -+ -+ if (ctx && no_heap_destroy) { -+ duk_gc(ctx, 0); -+ } -+ if (ctx && !no_heap_destroy) { -+ destroy_duktape_heap(ctx, alloc_provider); -+ } -+ ctx = NULL; -+ -+ return retval; -+ -+ /* -+ * Usage -+ */ -+ -+ usage: -+ fprintf(stderr, "Usage: duk [options] []\n" -+ "\n" -+ " -i enter interactive mode after executing argument file(s) / eval code\n" -+ " -e CODE evaluate code\n" -+ " -c FILE compile into bytecode and write to FILE (use with only one file argument)\n" -+ " -b allow bytecode input files (memory unsafe for invalid bytecode)\n" -+ " --run-stdin treat stdin like a file, i.e. compile full input (not line by line)\n" -+ " --verbose verbose messages to stderr\n" -+ " --restrict-memory use lower memory limit (used by test runner)\n" -+ " --alloc-default use Duktape default allocator\n" -+#if defined(DUK_CMDLINE_ALLOC_LOGGING) -+ " --alloc-logging use logging allocator, write alloc log to /tmp/duk-alloc-log.txt\n" -+#endif -+#if defined(DUK_CMDLINE_ALLOC_TORTURE) -+ " --alloc-torture use torture allocator\n" -+#endif -+#if defined(DUK_CMDLINE_ALLOC_HYBRID) -+ " --alloc-hybrid use hybrid allocator\n" -+#endif -+#if defined(DUK_CMDLINE_LOWMEM) -+ " --alloc-lowmem use pooled allocator (enabled by default for duk-low)\n" -+ " --lowmem-log write alloc log to /tmp/lowmem-alloc-log.txt\n" -+#endif -+#if defined(DUK_CMDLINE_DEBUGGER_SUPPORT) -+ " --debugger start example debugger\n" -+ " --reattach automatically reattach debugger on detach\n" -+#endif -+ " --recreate-heap recreate heap after every file\n" -+ " --no-heap-destroy force GC, but don't destroy heap at end (leak testing)\n" -+#if defined(DUK_CMDLINE_LINENOISE_COMPLETION) -+ " --no-auto-complete disable linenoise auto completion\n" -+#else -+ " --no-auto-complete disable linenoise auto completion [ignored, not supported]\n" -+#endif -+ "\n" -+ "If is omitted, interactive mode is started automatically.\n" -+ "\n" -+ "Input files can be either ECMAScript source files or bytecode files\n" -+ "(if -b is given). Bytecode files are not validated prior to loading,\n" -+ "so that incompatible or crafted files can cause memory unsafe behavior.\n" -+ "See discussion in\n" -+ "https://github.com/svaarala/duktape/blob/master/doc/bytecode.rst#memory-safety-and-bytecode-validation.\n"); -+ fflush(stderr); -+ exit(1); -+} -+ -+/* Example of how a native stack check can be implemented in a platform -+ * specific manner for DUK_USE_NATIVE_STACK_CHECK(). This example is for -+ * (Linux) pthreads, and rejects further native recursion if less than -+ * 16kB stack is left (conservative). -+ */ -+#if defined(DUK_CMDLINE_PTHREAD_STACK_CHECK) -+int duk_cmdline_stack_check(void) { -+ pthread_attr_t attr; -+ void *stackaddr; -+ size_t stacksize; -+ char *ptr; -+ char *ptr_base; -+ ptrdiff_t remain; -+ -+ (void) pthread_getattr_np(pthread_self(), &attr); -+ (void) pthread_attr_getstack(&attr, &stackaddr, &stacksize); -+ ptr = (char *) &stacksize; /* Rough estimate of current stack pointer. */ -+ ptr_base = (char *) stackaddr; -+ remain = ptr - ptr_base; -+ -+ /* HIGH ADDR ----- stackaddr + stacksize -+ * | -+ * | stack growth direction -+ * v -- ptr, approximate used size -+ * -+ * LOW ADDR ----- ptr_base, end of stack (lowest address) -+ */ -+ -+#if 0 -+ fprintf(stderr, "STACK CHECK: stackaddr=%p, stacksize=%ld, ptr=%p, remain=%ld\n", -+ stackaddr, (long) stacksize, (void *) ptr, (long) remain); -+ fflush(stderr); -+#endif -+ if (remain < 16384) { -+ return 1; -+ } -+ return 0; /* 0: no error, != 0: throw RangeError */ -+} -+#else -+int duk_cmdline_stack_check(void) { -+ return 0; -+} -+#endif -diff --git a/dist/source/examples/cmdline/duk_cmdline.h b/dist/source/examples/cmdline/duk_cmdline.h -new file mode 100644 -index 0000000..0c5c03d ---- /dev/null -+++ b/dist/source/examples/cmdline/duk_cmdline.h -@@ -0,0 +1,16 @@ -+#if !defined(DUK_CMDLINE_H_INCLUDED) -+#define DUK_CMDLINE_H_INCLUDED -+ -+/* Defined in duk_cmdline_lowmem.c. */ -+extern void *lowmem_pool_ptr; -+void lowmem_init(void); -+void lowmem_free(void); -+void lowmem_dump(void); -+void lowmem_register(duk_context *ctx); -+void lowmem_start_exec_timeout(void); -+void lowmem_clear_exec_timeout(void); -+void *lowmem_alloc_wrapped(void *udata, duk_size_t size); -+void *lowmem_realloc_wrapped(void *udata, void *ptr, duk_size_t size); -+void lowmem_free_wrapped(void *udata, void *ptr); -+ -+#endif /* DUK_CMDLINE_H_INCLUDED */ -diff --git a/dist/source/examples/cmdline/duk_cmdline_lowmem.c b/dist/source/examples/cmdline/duk_cmdline_lowmem.c -new file mode 100644 -index 0000000..3f3dea1 ---- /dev/null -+++ b/dist/source/examples/cmdline/duk_cmdline_lowmem.c -@@ -0,0 +1,1016 @@ -+/* -+ * Examples for low memory techniques -+ */ -+ -+#if defined(DUK_CMDLINE_LOWMEM) -+ -+#include -+#include -+#include -+#include -+#include "duktape.h" -+#include "duk_cmdline.h" -+#include "duk_alloc_pool.h" -+ -+#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) -+/* Pointer compression with ROM strings/objects: -+ * -+ * For now, use DUK_USE_ROM_OBJECTS to signal the need for compressed ROM -+ * pointers. DUK_USE_ROM_PTRCOMP_FIRST is provided for the ROM pointer -+ * compression range minimum to avoid duplication in user code. -+ */ -+#if 0 /* This extern declaration is provided by duktape.h, array provided by duktape.c. */ -+extern const void * const duk_rom_compressed_pointers[]; -+#endif -+static const void *duk__romptr_low = NULL; -+static const void *duk__romptr_high = NULL; -+#define DUK__ROMPTR_COMPRESSION -+#define DUK__ROMPTR_FIRST ((duk_uint_t) DUK_USE_ROM_PTRCOMP_FIRST) -+#endif -+ -+#define LOWMEM_NUM_POOLS 28 -+ -+#define LOWMEM_HEAP_SIZE (255 * 1024) -+ -+static const duk_pool_config lowmem_config[LOWMEM_NUM_POOLS] = { -+ { 8, 10 * 8, 0 }, -+ { 12, 600 * 12, 0 }, -+ { 16, 300 * 16, 0 }, -+ { 20, 300 * 20, 0 }, -+ { 24, 300 * 24, 0 }, -+ { 28, 250 * 28, 0 }, -+ { 32, 150 * 32, 0 }, -+ { 40, 150 * 40, 0 }, -+ { 48, 50 * 48, 0 }, -+ { 52, 50 * 52, 0 }, -+ { 56, 50 * 56, 0 }, -+ { 60, 50 * 60, 0 }, -+ { 64, 50 * 64, 0 }, -+ { 96, 50 * 96, 0 }, -+ { 196, 0, 196 }, /* duk_heap, with heap ptr compression, ROM strings+objects */ -+ { 232, 0, 232 }, /* duk_hthread, with heap ptr compression, ROM strings+objects */ -+ { 256, 16 * 256, 0 }, -+ { 288, 1 * 288, 0 }, -+ { 320, 1 * 320, 0 }, -+ { 400, 0, 400 }, /* duk_hthread, with heap ptr compression, RAM strings+objects */ -+ { 520, 0, 520 }, /* duk_heap, with heap ptr compression, RAM strings+objects */ -+ { 512, 16 * 512, 0 }, -+ { 768, 0, 768 }, /* initial value stack for packed duk_tval */ -+ { 1024, 6 * 1024, 0 }, -+ { 2048, 5 * 2048, 0 }, -+ { 4096, 3 * 4096, 0 }, -+ { 8192, 3 * 8192, 0 }, -+ { 16384, 1 * 16384, 0 }, -+}; -+ -+static duk_pool_state lowmem_state[LOWMEM_NUM_POOLS]; -+ -+static duk_pool_global lowmem_global; -+ -+void *lowmem_pool_ptr = NULL; -+ -+uint8_t *lowmem_ram = NULL; -+ -+static void *duk__lose_const(const void *ptr) { -+ /* Somewhat portable way of losing a const without warnings. -+ * Another approach is to cast through intptr_t, but that -+ * type is not always available. -+ */ -+ union { -+ const void *p; -+ void *q; -+ } u; -+ u.p = ptr; -+ return u.q; -+} -+ -+static void duk__safe_print_chars(const char *p, duk_size_t len, int until_nul) { -+ duk_size_t i; -+ -+ fprintf(stderr, "\""); -+ for (i = 0; i < len; i++) { -+ unsigned char x = (unsigned char) p[i]; -+ if (until_nul && x == 0U) { -+ break; -+ } -+ if (x < 0x20 || x >= 0x7e || x == '"' || x == '\'' || x == '\\') { -+ fprintf(stderr, "\\x%02x", (int) x); -+ } else { -+ fprintf(stderr, "%c", (char) x); -+ } -+ } -+ fprintf(stderr, "\""); -+} -+ -+ -+void lowmem_init(void) { -+ void *ptr; -+ -+ lowmem_ram = (uint8_t *) malloc(LOWMEM_HEAP_SIZE); -+ if (lowmem_ram == NULL) { -+ fprintf(stderr, "Failed to allocate lowmem heap\n"); -+ fflush(stderr); -+ exit(1); -+ } -+ -+ ptr = duk_alloc_pool_init((char *) lowmem_ram, -+ LOWMEM_HEAP_SIZE, -+ lowmem_config, -+ lowmem_state, -+ LOWMEM_NUM_POOLS, -+ &lowmem_global); -+ if (ptr == NULL) { -+ free(lowmem_ram); -+ lowmem_ram = NULL; -+ fprintf(stderr, "Failed to init lowmem pool\n"); -+ fflush(stderr); -+ exit(1); -+ } -+ -+ lowmem_pool_ptr = ptr; -+ -+#if defined(DUK__ROMPTR_COMPRESSION) -+ /* Scan ROM pointer range for faster detection of "is 'p' a ROM pointer" -+ * later on. -+ */ -+ if (1) { -+ const void * const * ptrs = (const void * const *) duk_rom_compressed_pointers; -+ duk__romptr_low = duk__romptr_high = (const void *) *ptrs; -+ while (*ptrs) { -+ if (*ptrs > duk__romptr_high) { -+ duk__romptr_high = (const void *) *ptrs; -+ } -+ if (*ptrs < duk__romptr_low) { -+ duk__romptr_low = (const void *) *ptrs; -+ } -+ ptrs++; -+ } -+ fprintf(stderr, "romptrs: low=%p high=%p\n", -+ (const void *) duk__romptr_low, (const void *) duk__romptr_high); -+ fflush(stderr); -+ } -+#endif -+} -+ -+void lowmem_free(void) { -+ if (lowmem_ram != NULL) { -+ free(lowmem_ram); -+ lowmem_ram = NULL; -+ } -+ lowmem_pool_ptr = NULL; -+} -+ -+static duk_ret_t lowmem__dump_binding(duk_context *ctx) { -+ lowmem_dump(); -+ return 0; -+} -+ -+void lowmem_dump(void) { -+ int i; -+ duk_pool_global_stats global_stats; -+ -+ for (i = 0; i < LOWMEM_NUM_POOLS; i++) { -+ duk_pool_state *s = &lowmem_state[i]; -+ duk_pool_stats stats; -+ -+ duk_alloc_pool_get_pool_stats(s, &stats); -+ -+ fprintf(stderr, " %2ld: %4ld %5ldB | free %4ld %5ldB | used %4ld %5ldB | waste %5ldB | hwm %4ld (%3ld%%)%s\n", -+ (long) i, (long) s->count, (long) s->size, -+ (long) stats.free_count, (long) stats.free_bytes, -+ (long) stats.used_count, (long) stats.used_bytes, -+ (long) stats.waste_bytes, (long) stats.hwm_used_count, -+ (long) ((double) stats.hwm_used_count / (double) s->count * 100.0), -+ (stats.hwm_used_count == s->count ? " !" : "")); -+ } -+ -+ /* This causes another walk over the individual pools which is a bit -+ * inelegant, but we want the highwater mark stats too. -+ */ -+ duk_alloc_pool_get_global_stats(&lowmem_global, &global_stats); -+ -+ fprintf(stderr, " TOTAL: %ld bytes used, %ld bytes waste, %ld bytes free, %ld bytes total; highwater %ld used, %ld waste\n", -+ (long) global_stats.used_bytes, (long) global_stats.waste_bytes, -+ (long) global_stats.free_bytes, (long) (global_stats.used_bytes + global_stats.free_bytes), -+ (long) global_stats.hwm_used_bytes, (long) global_stats.hwm_waste_bytes); -+ fflush(stderr); -+} -+ -+void lowmem_register(duk_context *ctx) { -+ duk_push_global_object(ctx); -+ duk_push_string(ctx, "dumpHeap"); -+ duk_push_c_function(ctx, lowmem__dump_binding, 0); -+ duk_def_prop(ctx, -3, DUK_DEFPROP_SET_WRITABLE | -+ DUK_DEFPROP_CLEAR_ENUMERABLE | -+ DUK_DEFPROP_SET_CONFIGURABLE | -+ DUK_DEFPROP_HAVE_VALUE); -+ duk_pop(ctx); -+} -+ -+/* -+ * Wrapped alloc functions -+ * -+ * Used to write an alloc log. -+ */ -+ -+static FILE *lowmem_alloc_log = NULL; -+ -+static void lowmem_write_alloc_log(const char *fmt, ...) { -+ va_list ap; -+ char buf[256]; -+ -+ va_start(ap, fmt); -+ vsnprintf(buf, sizeof(buf), fmt, ap); -+ buf[sizeof(buf) - 1] = (char) 0; -+ va_end(ap); -+ -+ if (lowmem_alloc_log == NULL) { -+ lowmem_alloc_log = fopen("/tmp/lowmem-alloc-log.txt", "wb"); -+ if (lowmem_alloc_log == NULL) { -+ fprintf(stderr, "WARNING: failed to write alloc log, ignoring\n"); -+ fflush(stderr); -+ return; -+ } -+ } -+ -+ (void) fwrite((const void *) buf, 1, strlen(buf), lowmem_alloc_log); -+ (void) fflush(lowmem_alloc_log); -+} -+ -+void *lowmem_alloc_wrapped(void *udata, duk_size_t size) { -+ void *ret = duk_alloc_pool(udata, size); -+ if (size > 0 && ret == NULL) { -+ lowmem_write_alloc_log("A FAIL %ld\n", (long) size); -+ } else if (ret == NULL) { -+ lowmem_write_alloc_log("A NULL %ld\n", (long) size); -+ } else { -+ lowmem_write_alloc_log("A %p %ld\n", ret, (long) size); -+ } -+ return ret; -+} -+ -+void *lowmem_realloc_wrapped(void *udata, void *ptr, duk_size_t size) { -+ void *ret = duk_realloc_pool(udata, ptr, size); -+ if (size > 0 && ret == NULL) { -+ if (ptr == NULL) { -+ lowmem_write_alloc_log("R NULL -1 FAIL %ld\n", (long) size); -+ } else { -+ lowmem_write_alloc_log("R %p -1 FAIL %ld\n", ptr, (long) size); -+ } -+ } else if (ret == NULL) { -+ if (ptr == NULL) { -+ lowmem_write_alloc_log("R NULL -1 NULL %ld\n", (long) size); -+ } else { -+ lowmem_write_alloc_log("R %p -1 NULL %ld\n", ptr, (long) size); -+ } -+ } else { -+ if (ptr == NULL) { -+ lowmem_write_alloc_log("R NULL -1 %p %ld\n", ret, (long) size); -+ } else { -+ lowmem_write_alloc_log("R %p -1 %p %ld\n", ptr, ret, (long) size); -+ } -+ } -+ return ret; -+} -+ -+void lowmem_free_wrapped(void *udata, void *ptr) { -+ duk_free_pool(udata, ptr); -+ if (ptr == NULL) { -+ /* Ignore. */ -+ } else { -+ lowmem_write_alloc_log("F %p -1\n", ptr); -+ } -+} -+ -+/* -+ * Example pointer compression functions. -+ * -+ * 'base' is chosen so that no non-NULL pointer results in a zero result -+ * which is reserved for NULL pointers. -+ */ -+ -+duk_uint16_t lowmem_enc16(void *ud, void *p) { -+ duk_uint32_t ret; -+ char *base = (char *) lowmem_ram - 4; -+ -+#if defined(DUK__ROMPTR_COMPRESSION) -+ if (p >= duk__romptr_low && p <= duk__romptr_high) { -+ /* The if-condition should be the fastest possible check -+ * for "is 'p' in ROM?". If pointer is in ROM, we'd like -+ * to compress it quickly. Here we just scan a ~1K array -+ * which is very bad for performance and for illustration -+ * only. -+ */ -+ const void * const * ptrs = duk_rom_compressed_pointers; -+ while (*ptrs) { -+ if (*ptrs == p) { -+ ret = (duk_uint32_t) DUK__ROMPTR_FIRST + (duk_uint32_t) (ptrs - duk_rom_compressed_pointers); -+#if 0 -+ fprintf(stderr, "lowmem_enc16: rom pointer: %p -> 0x%04lx\n", (void *) p, (long) ret); -+ fflush(stderr); -+#endif -+ return (duk_uint16_t) ret; -+ } -+ ptrs++; -+ } -+ -+ /* We should really never be here: Duktape should only be -+ * compressing pointers which are in the ROM compressed -+ * pointers list, which are known when configuring sources. -+ * We go on, causing a pointer compression error. -+ */ -+ fprintf(stderr, "lowmem_enc16: rom pointer: %p could not be compressed, should never happen\n", (void *) p); -+ fflush(stderr); -+ } -+#endif -+ -+ /* Userdata is not needed in this case but would be useful if heap -+ * pointer compression were used for multiple heaps. The userdata -+ * allows the callback to distinguish between heaps and their base -+ * pointers. -+ * -+ * If not needed, the userdata can be left out during compilation -+ * by simply ignoring the userdata argument of the pointer encode -+ * and decode macros. It is kept here so that any bugs in actually -+ * providing the value inside Duktape are revealed during compilation. -+ */ -+ (void) ud; -+#if 1 -+ /* Ensure that we always get the heap_udata given in heap creation. -+ * (Useful for Duktape development, not needed for user programs.) -+ */ -+ if (ud != (void *) lowmem_pool_ptr) { -+ fprintf(stderr, "invalid udata for lowmem_enc16: %p\n", ud); -+ fflush(stderr); -+ } -+#endif -+ -+ if (p == NULL) { -+ ret = 0; -+ } else { -+ ret = (duk_uint32_t) (((char *) p - base) >> 2); -+ } -+#if 0 -+ fprintf(stderr, "lowmem_enc16: %p -> %u\n", p, (unsigned int) ret); -+#endif -+ if (ret > 0xffffUL) { -+ fprintf(stderr, "Failed to compress pointer: %p (ret was %ld)\n", (void *) p, (long) ret); -+ fflush(stderr); -+ abort(); -+ } -+#if defined(DUK__ROMPTR_COMPRESSION) -+ if (ret >= (duk_uint32_t) DUK__ROMPTR_FIRST) { -+ fprintf(stderr, "Failed to compress pointer, in 16-bit range but matches romptr range: %p (ret was %ld)\n", (void *) p, (long) ret); -+ fflush(stderr); -+ abort(); -+ } -+#endif -+ return (duk_uint16_t) ret; -+} -+ -+void *lowmem_dec16(void *ud, duk_uint16_t x) { -+ void *ret; -+ char *base = (char *) lowmem_ram - 4; -+ -+#if defined(DUK__ROMPTR_COMPRESSION) -+ if (x >= (duk_uint16_t) DUK__ROMPTR_FIRST) { -+ /* This is a blind lookup, could check index validity. -+ * Duktape should never decompress a pointer which would -+ * be out-of-bounds here. -+ */ -+ ret = (void *) duk__lose_const(duk_rom_compressed_pointers[x - (duk_uint16_t) DUK__ROMPTR_FIRST]); -+#if 0 -+ fprintf(stderr, "lowmem_dec16: rom pointer: 0x%04lx -> %p\n", (long) x, ret); -+ fflush(stderr); -+#endif -+ return ret; -+ } -+#endif -+ -+ /* See userdata discussion in lowmem_enc16(). */ -+ (void) ud; -+#if 1 -+ /* Ensure that we always get the heap_udata given in heap creation. */ -+ if (ud != (void *) lowmem_pool_ptr) { -+ fprintf(stderr, "invalid udata for lowmem_dec16: %p\n", ud); -+ fflush(stderr); -+ } -+#endif -+ -+ if (x == 0) { -+ ret = NULL; -+ } else { -+ ret = (void *) (base + (((duk_uint32_t) x) << 2)); -+ } -+#if 0 -+ fprintf(stderr, "lowmem_dec16: %u -> %p\n", (unsigned int) x, ret); -+#endif -+ return ret; -+} -+ -+/* -+ * Simplified example of an external strings strategy where incoming strings -+ * are written sequentially into a fixed, memory mapped flash area. -+ * -+ * The example first scans if the string is already in the flash (which may -+ * happen if the same string is interned multiple times), then adds it to -+ * flash if there is space. -+ * -+ * This example is too slow to be used in a real world application: there -+ * should be e.g. a hash table to quickly check for strings that are already -+ * present in the string data (similarly to how string interning works in -+ * Duktape itself). -+ */ -+ -+static uint8_t lowmem_strdata[65536]; -+static size_t lowmem_strdata_used = 0; -+ -+const void *lowmem_extstr_check_1(const void *ptr, duk_size_t len) { -+ uint8_t *p, *p_end; -+ uint8_t initial; -+ uint8_t *ret; -+ size_t left; -+ -+ (void) duk__safe_print_chars; /* potentially unused */ -+ -+ if (len <= 3) { -+ /* It's not worth it to make very small strings external, as -+ * they would take the same space anyway. Also avoids zero -+ * length degenerate case. -+ */ -+ return NULL; -+ } -+ -+ /* -+ * Check if we already have the string. Be careful to compare for -+ * NUL terminator too, it is NOT present in 'ptr'. This algorithm -+ * is too simplistic and way too slow for actual use. -+ */ -+ -+ initial = ((const uint8_t *) ptr)[0]; -+ for (p = lowmem_strdata, p_end = p + lowmem_strdata_used; p != p_end; p++) { -+ if (*p != initial) { -+ continue; -+ } -+ left = (size_t) (p_end - p); -+ if (left >= len + 1 && -+ memcmp(p, ptr, len) == 0 && -+ p[len] == 0) { -+ ret = p; -+#if 0 -+ fprintf(stderr, "lowmem_extstr_check_1: ptr=%p, len=%ld ", -+ (void *) ptr, (long) len); -+ duk__safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); -+ fprintf(stderr, " -> existing %p (used=%ld)\n", -+ (void *) ret, (long) lowmem_strdata_used); -+#endif -+ return ret; -+ } -+ } -+ -+ /* -+ * Not present yet, check if we have space. Again, be careful to -+ * ensure there is space for a NUL following the input data. -+ */ -+ -+ if (lowmem_strdata_used + len + 1 > sizeof(lowmem_strdata)) { -+#if 0 -+ fprintf(stderr, "lowmem_extstr_check_1: ptr=%p, len=%ld ", (void *) ptr, (long) len); -+ duk__safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); -+ fprintf(stderr, " -> no space (used=%ld)\n", (long) lowmem_strdata_used); -+#endif -+ return NULL; -+ } -+ -+ /* -+ * There is space, add the string to our collection, being careful -+ * to append the NUL. -+ */ -+ -+ ret = lowmem_strdata + lowmem_strdata_used; -+ memcpy(ret, ptr, len); -+ ret[len] = (uint8_t) 0; -+ lowmem_strdata_used += len + 1; -+ -+#if 0 -+ fprintf(stderr, "lowmem_extstr_check_1: ptr=%p, len=%ld -> ", (void *) ptr, (long) len); -+ duk__safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); -+ fprintf(stderr, " -> %p (used=%ld)\n", (void *) ret, (long) lowmem_strdata_used); -+#endif -+ return (const void *) ret; -+} -+ -+void lowmem_extstr_free_1(const void *ptr) { -+ (void) ptr; -+#if 0 -+ fprintf(stderr, "lowmem_extstr_free_1: freeing extstr %p -> ", ptr); -+ duk__safe_print_chars((const char *) ptr, DUK_SIZE_MAX, 1 /*until_nul*/); -+ fprintf(stderr, "\n"); -+#endif -+} -+ -+/* -+ * Simplified example of an external strings strategy where a set of strings -+ * is gathered during application compile time and baked into the application -+ * binary. -+ * -+ * Duktape built-in strings are available from duk_source_meta.json in a -+ * prepared source directory, see tools/duk_meta_to_strarray.py. There -+ * may also be a lot of application specific strings, e.g. those used by -+ * application specific APIs. These must be gathered through some other -+ * means, see e.g. tools/scan_strings.py. -+ */ -+ -+static const char *strdata_duk_builtin_strings[] = { -+ /* -+ * These strings are from tools/duk_meta_to_strarray.py -+ */ -+ -+ "Logger", -+ "Thread", -+ "Pointer", -+ "Buffer", -+ "DecEnv", -+ "ObjEnv", -+ "", -+ "global", -+ "Arguments", -+ "JSON", -+ "Math", -+ "Error", -+ "RegExp", -+ "Date", -+ "Number", -+ "Boolean", -+ "String", -+ "Array", -+ "Function", -+ "Object", -+ "Null", -+ "Undefined", -+ "{_func:true}", -+ "{\x22" "_func\x22" ":true}", -+ "{\x22" "_ninf\x22" ":true}", -+ "{\x22" "_inf\x22" ":true}", -+ "{\x22" "_nan\x22" ":true}", -+ "{\x22" "_undef\x22" ":true}", -+ "toLogString", -+ "clog", -+ "l", -+ "n", -+ "fatal", -+ "error", -+ "warn", -+ "debug", -+ "trace", -+ "raw", -+ "fmt", -+ "current", -+ "resume", -+ "compact", -+ "jc", -+ "jx", -+ "base64", -+ "hex", -+ "dec", -+ "enc", -+ "fin", -+ "gc", -+ "act", -+ "info", -+ "version", -+ "env", -+ "modLoaded", -+ "modSearch", -+ "errThrow", -+ "errCreate", -+ "compile", -+ "\x82" "Regbase", -+ "\x82" "Thread", -+ "\x82" "Handler", -+ "\x82" "Finalizer", -+ "\x82" "Callee", -+ "\x82" "Map", -+ "\x82" "Args", -+ "\x82" "This", -+ "\x82" "Pc2line", -+ "\x82" "Source", -+ "\x82" "Varenv", -+ "\x82" "Lexenv", -+ "\x82" "Varmap", -+ "\x82" "Formals", -+ "\x82" "Bytecode", -+ "\x82" "Next", -+ "\x82" "Target", -+ "\x82" "Value", -+ "pointer", -+ "buffer", -+ "\x82" "Tracedata", -+ "lineNumber", -+ "fileName", -+ "pc", -+ "stack", -+ "ThrowTypeError", -+ "Duktape", -+ "id", -+ "require", -+ "__proto__", -+ "setPrototypeOf", -+ "ownKeys", -+ "enumerate", -+ "deleteProperty", -+ "has", -+ "Proxy", -+ "callee", -+ "Invalid Date", -+ "[...]", -+ "\x0a" "\x09", -+ " ", -+ ",", -+ "-0", -+ "+0", -+ "0", -+ "-Infinity", -+ "+Infinity", -+ "Infinity", -+ "object", -+ "string", -+ "number", -+ "boolean", -+ "undefined", -+ "stringify", -+ "tan", -+ "sqrt", -+ "sin", -+ "round", -+ "random", -+ "pow", -+ "min", -+ "max", -+ "log", -+ "floor", -+ "exp", -+ "cos", -+ "ceil", -+ "atan2", -+ "atan", -+ "asin", -+ "acos", -+ "abs", -+ "SQRT2", -+ "SQRT1_2", -+ "PI", -+ "LOG10E", -+ "LOG2E", -+ "LN2", -+ "LN10", -+ "E", -+ "message", -+ "name", -+ "input", -+ "index", -+ "(?:)", -+ "lastIndex", -+ "multiline", -+ "ignoreCase", -+ "source", -+ "test", -+ "exec", -+ "toGMTString", -+ "setYear", -+ "getYear", -+ "toJSON", -+ "toISOString", -+ "toUTCString", -+ "setUTCFullYear", -+ "setFullYear", -+ "setUTCMonth", -+ "setMonth", -+ "setUTCDate", -+ "setDate", -+ "setUTCHours", -+ "setHours", -+ "setUTCMinutes", -+ "setMinutes", -+ "setUTCSeconds", -+ "setSeconds", -+ "setUTCMilliseconds", -+ "setMilliseconds", -+ "setTime", -+ "getTimezoneOffset", -+ "getUTCMilliseconds", -+ "getMilliseconds", -+ "getUTCSeconds", -+ "getSeconds", -+ "getUTCMinutes", -+ "getMinutes", -+ "getUTCHours", -+ "getHours", -+ "getUTCDay", -+ "getDay", -+ "getUTCDate", -+ "getDate", -+ "getUTCMonth", -+ "getMonth", -+ "getUTCFullYear", -+ "getFullYear", -+ "getTime", -+ "toLocaleTimeString", -+ "toLocaleDateString", -+ "toTimeString", -+ "toDateString", -+ "now", -+ "UTC", -+ "parse", -+ "toPrecision", -+ "toExponential", -+ "toFixed", -+ "POSITIVE_INFINITY", -+ "NEGATIVE_INFINITY", -+ "NaN", -+ "MIN_VALUE", -+ "MAX_VALUE", -+ "substr", -+ "trim", -+ "toLocaleUpperCase", -+ "toUpperCase", -+ "toLocaleLowerCase", -+ "toLowerCase", -+ "substring", -+ "split", -+ "search", -+ "replace", -+ "match", -+ "localeCompare", -+ "charCodeAt", -+ "charAt", -+ "fromCharCode", -+ "reduceRight", -+ "reduce", -+ "filter", -+ "map", -+ "forEach", -+ "some", -+ "every", -+ "lastIndexOf", -+ "indexOf", -+ "unshift", -+ "splice", -+ "sort", -+ "slice", -+ "shift", -+ "reverse", -+ "push", -+ "pop", -+ "join", -+ "concat", -+ "isArray", -+ "arguments", -+ "caller", -+ "bind", -+ "call", -+ "apply", -+ "propertyIsEnumerable", -+ "isPrototypeOf", -+ "hasOwnProperty", -+ "valueOf", -+ "toLocaleString", -+ "toString", -+ "constructor", -+ "set", -+ "get", -+ "enumerable", -+ "configurable", -+ "writable", -+ "value", -+ "keys", -+ "isExtensible", -+ "isFrozen", -+ "isSealed", -+ "preventExtensions", -+ "freeze", -+ "seal", -+ "defineProperties", -+ "defineProperty", -+ "create", -+ "getOwnPropertyNames", -+ "getOwnPropertyDescriptor", -+ "getPrototypeOf", -+ "prototype", -+ "length", -+ "alert", -+ "print", -+ "unescape", -+ "escape", -+ "encodeURIComponent", -+ "encodeURI", -+ "decodeURIComponent", -+ "decodeURI", -+ "isFinite", -+ "isNaN", -+ "parseFloat", -+ "parseInt", -+ "eval", -+ "URIError", -+ "TypeError", -+ "SyntaxError", -+ "ReferenceError", -+ "RangeError", -+ "EvalError", -+ "break", -+ "case", -+ "catch", -+ "continue", -+ "debugger", -+ "default", -+ "delete", -+ "do", -+ "else", -+ "finally", -+ "for", -+ "function", -+ "if", -+ "in", -+ "instanceof", -+ "new", -+ "return", -+ "switch", -+ "this", -+ "throw", -+ "try", -+ "typeof", -+ "var", -+ "void", -+ "while", -+ "with", -+ "class", -+ "const", -+ "enum", -+ "export", -+ "extends", -+ "import", -+ "super", -+ "null", -+ "true", -+ "false", -+ "implements", -+ "interface", -+ "let", -+ "package", -+ "private", -+ "protected", -+ "public", -+ "static", -+ "yield", -+ -+ /* -+ * These strings are manually added, and would be gathered in some -+ * application specific manner. -+ */ -+ -+ "foo", -+ "bar", -+ "quux", -+ "enableFrob", -+ "disableFrob" -+ /* ... */ -+}; -+ -+const void *lowmem_extstr_check_2(const void *ptr, duk_size_t len) { -+ int i, n; -+ -+ (void) duk__safe_print_chars; /* potentially unused */ -+ -+ /* Linear scan. An actual implementation would need some acceleration -+ * structure, e.g. select a sublist based on first character. -+ * -+ * NOTE: input string (behind 'ptr' with 'len' bytes) DOES NOT have a -+ * trailing NUL character. Any strings returned from this function -+ * MUST have a trailing NUL character. -+ */ -+ -+ n = (int) (sizeof(strdata_duk_builtin_strings) / sizeof(const char *)); -+ for (i = 0; i < n; i++) { -+ const char *str; -+ -+ str = strdata_duk_builtin_strings[i]; -+ if (strlen(str) == len && memcmp(ptr, (const void *) str, len) == 0) { -+#if 0 -+ fprintf(stderr, "lowmem_extstr_check_2: ptr=%p, len=%ld ", -+ (void *) ptr, (long) len); -+ duk__safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); -+ fprintf(stderr, " -> constant string index %ld\n", (long) i); -+#endif -+ return (void *) duk__lose_const(strdata_duk_builtin_strings[i]); -+ } -+ } -+ -+#if 0 -+ fprintf(stderr, "lowmem_extstr_check_2: ptr=%p, len=%ld ", -+ (void *) ptr, (long) len); -+ duk__safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); -+ fprintf(stderr, " -> not found\n"); -+#endif -+ return NULL; -+} -+ -+void lowmem_extstr_free_2(const void *ptr) { -+ (void) ptr; -+#if 0 -+ fprintf(stderr, "lowmem_extstr_free_2: freeing extstr %p -> ", ptr); -+ duk__safe_print_chars((const char *) ptr, DUK_SIZE_MAX, 1 /*until_nul*/); -+ fprintf(stderr, "\n"); -+#endif -+} -+ -+/* -+ * External strings strategy intended for valgrind testing: external strings -+ * are allocated using malloc()/free() so that valgrind can be used to ensure -+ * that strings are e.g. freed exactly once. -+ */ -+ -+const void *lowmem_extstr_check_3(const void *ptr, duk_size_t len) { -+ duk_uint8_t *ret; -+ -+ (void) duk__safe_print_chars; /* potentially unused */ -+ -+ ret = malloc((size_t) len + 1); -+ if (ret == NULL) { -+#if 0 -+ fprintf(stderr, "lowmem_extstr_check_3: ptr=%p, len=%ld ", -+ (void *) ptr, (long) len); -+ duk__safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); -+ fprintf(stderr, " -> malloc failed, return NULL\n"); -+#endif -+ return (const void *) NULL; -+ } -+ -+ if (len > 0) { -+ memcpy((void *) ret, ptr, (size_t) len); -+ } -+ ret[len] = (duk_uint8_t) 0; -+ -+#if 0 -+ fprintf(stderr, "lowmem_extstr_check_3: ptr=%p, len=%ld ", -+ (void *) ptr, (long) len); -+ duk__safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); -+ fprintf(stderr, " -> %p\n", (void *) ret); -+#endif -+ return (const void *) ret; -+} -+ -+void lowmem_extstr_free_3(const void *ptr) { -+ (void) ptr; -+#if 0 -+ fprintf(stderr, "lowmem_extstr_free_3: freeing extstr %p -> ", ptr); -+ duk__safe_print_chars((const char *) ptr, DUK_SIZE_MAX, 1 /*until_nul*/); -+ fprintf(stderr, "\n"); -+#endif -+ free((void *) duk__lose_const(ptr)); -+} -+ -+/* -+ * Execution timeout example -+ */ -+ -+#define AJSHEAP_EXEC_TIMEOUT 5 /* seconds */ -+ -+static time_t curr_pcall_start = 0; -+static long exec_timeout_check_counter = 0; -+ -+void lowmem_start_exec_timeout(void) { -+ curr_pcall_start = time(NULL); -+} -+ -+void lowmem_clear_exec_timeout(void) { -+ curr_pcall_start = 0; -+} -+ -+duk_bool_t lowmem_exec_timeout_check(void *udata) { -+ time_t now = time(NULL); -+ time_t diff = now - curr_pcall_start; -+ -+ (void) udata; /* not needed */ -+ -+ exec_timeout_check_counter++; -+#if 0 -+ fprintf(stderr, "exec timeout check %ld: now=%ld, start=%ld, diff=%ld\n", -+ (long) exec_timeout_check_counter, (long) now, (long) curr_pcall_start, (long) diff); -+ fflush(stderr); -+#endif -+ -+ if (curr_pcall_start == 0) { -+ /* protected call not yet running */ -+ return 0; -+ } -+ if (diff > AJSHEAP_EXEC_TIMEOUT) { -+ return 1; -+ } -+ return 0; -+} -+ -+#else /* DUK_CMDLINE_LOWMEM */ -+ -+int duk_lowmem_dummy = 0; /* to avoid empty source file */ -+ -+#endif /* DUK_CMDLINE_LOWMEM */ -diff --git a/dist/source/examples/codepage-conv/README.rst b/dist/source/examples/codepage-conv/README.rst -new file mode 100644 -index 0000000..98b53d2 ---- /dev/null -+++ b/dist/source/examples/codepage-conv/README.rst -@@ -0,0 +1,8 @@ -+Codepage conversion example -+=========================== -+ -+Example of how to convert an 8-bit input string (e.g. ISO-8859-1 or Windows -+codepage 1252) into CESU-8 without using an external library like iconv. -+ -+This is useful e.g. when compiling non-UTF-8 source code which cannot be -+converted to UTF-8 (CESU-8) at build time. -diff --git a/dist/source/examples/codepage-conv/duk_codepage_conv.c b/dist/source/examples/codepage-conv/duk_codepage_conv.c -new file mode 100644 -index 0000000..315f042 ---- /dev/null -+++ b/dist/source/examples/codepage-conv/duk_codepage_conv.c -@@ -0,0 +1,54 @@ -+/* -+ * Convert an 8-bit input string (e.g. ISO-8859-1) into CESU-8. -+ * Calling code supplies the "code page" as a 256-entry array of -+ * codepoints for the conversion. -+ * -+ * This is useful when input data is in non-UTF-8 format and must -+ * be converted at runtime, e.g. when compiling non-UTF-8 source -+ * code. Another alternative is to use e.g. iconv. -+ */ -+ -+#include "duktape.h" -+ -+/* Decode an 8-bit string using 'codepage' into Unicode codepoints and -+ * re-encode into CESU-8. Codepage argument must point to a 256-entry -+ * table. Only supports BMP (codepoints U+0000 to U+FFFF). -+ */ -+void duk_decode_string_codepage(duk_context *ctx, const char *str, size_t len, unsigned int *codepage) { -+ unsigned char *tmp; -+ size_t tmplen, i; -+ unsigned char *p; -+ unsigned int cp; -+ -+ tmplen = 3 * len; /* max expansion is 1 input byte -> 3 output bytes */ -+ if (tmplen / 3 != len) { -+ /* Temporary buffer length wraps. */ -+ (void) duk_error(ctx, DUK_ERR_RANGE_ERROR, "input string too long"); -+ return; -+ } -+ -+ tmp = (unsigned char *) duk_push_fixed_buffer(ctx, tmplen); -+ -+ for (i = 0, p = tmp; i < len; i++) { -+ cp = codepage[((unsigned char *) str)[i]] & 0xffffUL; -+ if (cp < 0x80UL) { -+ *p++ = (unsigned char) cp; -+ } else if (cp < 0x800UL) { -+ *p++ = (unsigned char) (0xc0 + ((cp >> 6) & 0x1f)); -+ *p++ = (unsigned char) (0x80 + (cp & 0x3f)); -+ } else { -+ /* In CESU-8 all codepoints in [0x0000,0xFFFF] are -+ * allowed, including surrogates. -+ */ -+ *p++ = (unsigned char) (0xe0 + ((cp >> 12) & 0x0f)); -+ *p++ = (unsigned char) (0x80 + ((cp >> 6) & 0x3f)); -+ *p++ = (unsigned char) (0x80 + (cp & 0x3f)); -+ } -+ } -+ -+ duk_push_lstring(ctx, (const char *) tmp, (duk_size_t) (p - tmp)); -+ -+ /* [ ... tmp res ] */ -+ -+ duk_remove(ctx, -2); -+} -diff --git a/dist/source/examples/codepage-conv/duk_codepage_conv.h b/dist/source/examples/codepage-conv/duk_codepage_conv.h -new file mode 100644 -index 0000000..052d27f ---- /dev/null -+++ b/dist/source/examples/codepage-conv/duk_codepage_conv.h -@@ -0,0 +1,8 @@ -+#if !defined(DUK_CODEPAGE_CONV_H_INCLUDED) -+#define DUK_CODEPAGE_CONV_H_INCLUDED -+ -+#include "duktape.h" -+ -+void duk_decode_string_codepage(duk_context *ctx, const char *str, size_t len, unsigned int *codepage); -+ -+#endif /* DUK_CODEPAGE_CONV_H_INCLUDED */ -diff --git a/dist/source/examples/codepage-conv/test.c b/dist/source/examples/codepage-conv/test.c -new file mode 100644 -index 0000000..7a89dd4 ---- /dev/null -+++ b/dist/source/examples/codepage-conv/test.c -@@ -0,0 +1,298 @@ -+#include "duktape.h" -+#include "duk_codepage_conv.h" -+ -+/* http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT */ -+unsigned int cp1252[256] = { -+ (unsigned int) 0x0000, -+ (unsigned int) 0x0001, -+ (unsigned int) 0x0002, -+ (unsigned int) 0x0003, -+ (unsigned int) 0x0004, -+ (unsigned int) 0x0005, -+ (unsigned int) 0x0006, -+ (unsigned int) 0x0007, -+ (unsigned int) 0x0008, -+ (unsigned int) 0x0009, -+ (unsigned int) 0x000A, -+ (unsigned int) 0x000B, -+ (unsigned int) 0x000C, -+ (unsigned int) 0x000D, -+ (unsigned int) 0x000E, -+ (unsigned int) 0x000F, -+ (unsigned int) 0x0010, -+ (unsigned int) 0x0011, -+ (unsigned int) 0x0012, -+ (unsigned int) 0x0013, -+ (unsigned int) 0x0014, -+ (unsigned int) 0x0015, -+ (unsigned int) 0x0016, -+ (unsigned int) 0x0017, -+ (unsigned int) 0x0018, -+ (unsigned int) 0x0019, -+ (unsigned int) 0x001A, -+ (unsigned int) 0x001B, -+ (unsigned int) 0x001C, -+ (unsigned int) 0x001D, -+ (unsigned int) 0x001E, -+ (unsigned int) 0x001F, -+ (unsigned int) 0x0020, -+ (unsigned int) 0x0021, -+ (unsigned int) 0x0022, -+ (unsigned int) 0x0023, -+ (unsigned int) 0x0024, -+ (unsigned int) 0x0025, -+ (unsigned int) 0x0026, -+ (unsigned int) 0x0027, -+ (unsigned int) 0x0028, -+ (unsigned int) 0x0029, -+ (unsigned int) 0x002A, -+ (unsigned int) 0x002B, -+ (unsigned int) 0x002C, -+ (unsigned int) 0x002D, -+ (unsigned int) 0x002E, -+ (unsigned int) 0x002F, -+ (unsigned int) 0x0030, -+ (unsigned int) 0x0031, -+ (unsigned int) 0x0032, -+ (unsigned int) 0x0033, -+ (unsigned int) 0x0034, -+ (unsigned int) 0x0035, -+ (unsigned int) 0x0036, -+ (unsigned int) 0x0037, -+ (unsigned int) 0x0038, -+ (unsigned int) 0x0039, -+ (unsigned int) 0x003A, -+ (unsigned int) 0x003B, -+ (unsigned int) 0x003C, -+ (unsigned int) 0x003D, -+ (unsigned int) 0x003E, -+ (unsigned int) 0x003F, -+ (unsigned int) 0x0040, -+ (unsigned int) 0x0041, -+ (unsigned int) 0x0042, -+ (unsigned int) 0x0043, -+ (unsigned int) 0x0044, -+ (unsigned int) 0x0045, -+ (unsigned int) 0x0046, -+ (unsigned int) 0x0047, -+ (unsigned int) 0x0048, -+ (unsigned int) 0x0049, -+ (unsigned int) 0x004A, -+ (unsigned int) 0x004B, -+ (unsigned int) 0x004C, -+ (unsigned int) 0x004D, -+ (unsigned int) 0x004E, -+ (unsigned int) 0x004F, -+ (unsigned int) 0x0050, -+ (unsigned int) 0x0051, -+ (unsigned int) 0x0052, -+ (unsigned int) 0x0053, -+ (unsigned int) 0x0054, -+ (unsigned int) 0x0055, -+ (unsigned int) 0x0056, -+ (unsigned int) 0x0057, -+ (unsigned int) 0x0058, -+ (unsigned int) 0x0059, -+ (unsigned int) 0x005A, -+ (unsigned int) 0x005B, -+ (unsigned int) 0x005C, -+ (unsigned int) 0x005D, -+ (unsigned int) 0x005E, -+ (unsigned int) 0x005F, -+ (unsigned int) 0x0060, -+ (unsigned int) 0x0061, -+ (unsigned int) 0x0062, -+ (unsigned int) 0x0063, -+ (unsigned int) 0x0064, -+ (unsigned int) 0x0065, -+ (unsigned int) 0x0066, -+ (unsigned int) 0x0067, -+ (unsigned int) 0x0068, -+ (unsigned int) 0x0069, -+ (unsigned int) 0x006A, -+ (unsigned int) 0x006B, -+ (unsigned int) 0x006C, -+ (unsigned int) 0x006D, -+ (unsigned int) 0x006E, -+ (unsigned int) 0x006F, -+ (unsigned int) 0x0070, -+ (unsigned int) 0x0071, -+ (unsigned int) 0x0072, -+ (unsigned int) 0x0073, -+ (unsigned int) 0x0074, -+ (unsigned int) 0x0075, -+ (unsigned int) 0x0076, -+ (unsigned int) 0x0077, -+ (unsigned int) 0x0078, -+ (unsigned int) 0x0079, -+ (unsigned int) 0x007A, -+ (unsigned int) 0x007B, -+ (unsigned int) 0x007C, -+ (unsigned int) 0x007D, -+ (unsigned int) 0x007E, -+ (unsigned int) 0x007F, -+ (unsigned int) 0x20AC, -+ (unsigned int) 0xFFFD, /* undefined */ -+ (unsigned int) 0x201A, -+ (unsigned int) 0x0192, -+ (unsigned int) 0x201E, -+ (unsigned int) 0x2026, -+ (unsigned int) 0x2020, -+ (unsigned int) 0x2021, -+ (unsigned int) 0x02C6, -+ (unsigned int) 0x2030, -+ (unsigned int) 0x0160, -+ (unsigned int) 0x2039, -+ (unsigned int) 0x0152, -+ (unsigned int) 0xFFFD, /* undefined */ -+ (unsigned int) 0x017D, -+ (unsigned int) 0xFFFD, /* undefined */ -+ (unsigned int) 0xFFFD, /* undefined */ -+ (unsigned int) 0x2018, -+ (unsigned int) 0x2019, -+ (unsigned int) 0x201C, -+ (unsigned int) 0x201D, -+ (unsigned int) 0x2022, -+ (unsigned int) 0x2013, -+ (unsigned int) 0x2014, -+ (unsigned int) 0x02DC, -+ (unsigned int) 0x2122, -+ (unsigned int) 0x0161, -+ (unsigned int) 0x203A, -+ (unsigned int) 0x0153, -+ (unsigned int) 0xFFFD, /* undefined */ -+ (unsigned int) 0x017E, -+ (unsigned int) 0x0178, -+ (unsigned int) 0x00A0, -+ (unsigned int) 0x00A1, -+ (unsigned int) 0x00A2, -+ (unsigned int) 0x00A3, -+ (unsigned int) 0x00A4, -+ (unsigned int) 0x00A5, -+ (unsigned int) 0x00A6, -+ (unsigned int) 0x00A7, -+ (unsigned int) 0x00A8, -+ (unsigned int) 0x00A9, -+ (unsigned int) 0x00AA, -+ (unsigned int) 0x00AB, -+ (unsigned int) 0x00AC, -+ (unsigned int) 0x00AD, -+ (unsigned int) 0x00AE, -+ (unsigned int) 0x00AF, -+ (unsigned int) 0x00B0, -+ (unsigned int) 0x00B1, -+ (unsigned int) 0x00B2, -+ (unsigned int) 0x00B3, -+ (unsigned int) 0x00B4, -+ (unsigned int) 0x00B5, -+ (unsigned int) 0x00B6, -+ (unsigned int) 0x00B7, -+ (unsigned int) 0x00B8, -+ (unsigned int) 0x00B9, -+ (unsigned int) 0x00BA, -+ (unsigned int) 0x00BB, -+ (unsigned int) 0x00BC, -+ (unsigned int) 0x00BD, -+ (unsigned int) 0x00BE, -+ (unsigned int) 0x00BF, -+ (unsigned int) 0x00C0, -+ (unsigned int) 0x00C1, -+ (unsigned int) 0x00C2, -+ (unsigned int) 0x00C3, -+ (unsigned int) 0x00C4, -+ (unsigned int) 0x00C5, -+ (unsigned int) 0x00C6, -+ (unsigned int) 0x00C7, -+ (unsigned int) 0x00C8, -+ (unsigned int) 0x00C9, -+ (unsigned int) 0x00CA, -+ (unsigned int) 0x00CB, -+ (unsigned int) 0x00CC, -+ (unsigned int) 0x00CD, -+ (unsigned int) 0x00CE, -+ (unsigned int) 0x00CF, -+ (unsigned int) 0x00D0, -+ (unsigned int) 0x00D1, -+ (unsigned int) 0x00D2, -+ (unsigned int) 0x00D3, -+ (unsigned int) 0x00D4, -+ (unsigned int) 0x00D5, -+ (unsigned int) 0x00D6, -+ (unsigned int) 0x00D7, -+ (unsigned int) 0x00D8, -+ (unsigned int) 0x00D9, -+ (unsigned int) 0x00DA, -+ (unsigned int) 0x00DB, -+ (unsigned int) 0x00DC, -+ (unsigned int) 0x00DD, -+ (unsigned int) 0x00DE, -+ (unsigned int) 0x00DF, -+ (unsigned int) 0x00E0, -+ (unsigned int) 0x00E1, -+ (unsigned int) 0x00E2, -+ (unsigned int) 0x00E3, -+ (unsigned int) 0x00E4, -+ (unsigned int) 0x00E5, -+ (unsigned int) 0x00E6, -+ (unsigned int) 0x00E7, -+ (unsigned int) 0x00E8, -+ (unsigned int) 0x00E9, -+ (unsigned int) 0x00EA, -+ (unsigned int) 0x00EB, -+ (unsigned int) 0x00EC, -+ (unsigned int) 0x00ED, -+ (unsigned int) 0x00EE, -+ (unsigned int) 0x00EF, -+ (unsigned int) 0x00F0, -+ (unsigned int) 0x00F1, -+ (unsigned int) 0x00F2, -+ (unsigned int) 0x00F3, -+ (unsigned int) 0x00F4, -+ (unsigned int) 0x00F5, -+ (unsigned int) 0x00F6, -+ (unsigned int) 0x00F7, -+ (unsigned int) 0x00F8, -+ (unsigned int) 0x00F9, -+ (unsigned int) 0x00FA, -+ (unsigned int) 0x00FB, -+ (unsigned int) 0x00FC, -+ (unsigned int) 0x00FD, -+ (unsigned int) 0x00FE, -+ (unsigned int) 0x00FF -+}; -+ -+/* Exercise all 3 byte lengths: any ASCII character is 1 byte, 0xFC maps to -+ * U+00FC which is 2 bytes, and 0x80 maps to U+20AC which is 3 bytes. -+ */ -+static const char *example_source = "print('Hello w\xfcrld - \x80');"; -+ -+static duk_ret_t duk__print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ return 0; -+} -+ -+/* Example: compile and run test source encoded in Windows codepage 1252. */ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ -+ (void) argc; (void) argv; -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { -+ printf("Failed to create Duktape heap.\n"); -+ return 1; -+ } -+ -+ /* Minimal print() provider. */ -+ duk_push_c_function(ctx, duk__print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ -+ duk_decode_string_codepage(ctx, example_source, strlen(example_source), cp1252); -+ duk_eval_noresult(ctx); -+ -+ duk_destroy_heap(ctx); -+ return 0; -+} -diff --git a/dist/source/examples/coffee/README.rst b/dist/source/examples/coffee/README.rst -new file mode 100644 -index 0000000..f147522 ---- /dev/null -+++ b/dist/source/examples/coffee/README.rst -@@ -0,0 +1,10 @@ -+===================== -+Coffeescript examples -+===================== -+ -+A few tests to see how CoffeeScript works with Duktape. Just convert the -+Coffeescript files to Javascript with the ``Makefile.coffee`` in the -+distributable, or manually:: -+ -+ $ coffee -c hello.coffee -+ $ cat hello.js -diff --git a/dist/source/examples/coffee/globals.coffee b/dist/source/examples/coffee/globals.coffee -new file mode 100644 -index 0000000..25773cd ---- /dev/null -+++ b/dist/source/examples/coffee/globals.coffee -@@ -0,0 +1,7 @@ -+ -+print '*** All globals' -+print(name) for name in Object.getOwnPropertyNames(this) -+ -+print '*** Globals with a short name (<= 8 chars)' -+print(name) for name in Object.getOwnPropertyNames(this) when name.length <= 8 -+ -diff --git a/dist/source/examples/coffee/hello.coffee b/dist/source/examples/coffee/hello.coffee -new file mode 100644 -index 0000000..088ed8d ---- /dev/null -+++ b/dist/source/examples/coffee/hello.coffee -@@ -0,0 +1,2 @@ -+print 'Hello world!' -+print 'version: ' + Duktape.version -diff --git a/dist/source/examples/coffee/mandel.coffee b/dist/source/examples/coffee/mandel.coffee -new file mode 100644 -index 0000000..8e3e170 ---- /dev/null -+++ b/dist/source/examples/coffee/mandel.coffee -@@ -0,0 +1,28 @@ -+mandel = (x0, y0, x1, y1, w, h, maxiter) -> -+ [dx, dy] = [(x1 - x0) / w, (y1 - y0) / h] -+ res = [] -+ -+ y = y0 -+ for yc in [0..h-1] -+ x = x0 -+ for xc in [0..w-1] -+ [xx, yy] = [x, y] -+ c = '*' -+ for i in [0..maxiter-1] -+ # (xx+i*yy)^2 + (x+i*y) = xx^2 + i*2*xx*yy - yy^2 + x + i*y -+ # = (xx^2 - yy^2 + x) + i*(2*xx*yy + y) -+ [xx2, yy2] = [xx*xx, yy*yy] -+ if xx2 + yy2 >= 4.0 -+ c = '.' -+ break -+ [xx, yy] = [xx2 - yy2 + x, 2*xx*yy + y] -+ res.push(c) -+ x += dx -+ res.push('\n') -+ y += dy -+ -+ print(res.join('')) -+ return -+ -+mandel(-2, 2, 2, -2, 200, 100, 1000) -+ -diff --git a/dist/source/examples/cpp-exceptions/README.rst b/dist/source/examples/cpp-exceptions/README.rst -new file mode 100644 -index 0000000..fb969da ---- /dev/null -+++ b/dist/source/examples/cpp-exceptions/README.rst -@@ -0,0 +1,29 @@ -+========================================= -+C++ exceptions for long control transfers -+========================================= -+ -+Normally Duktape uses ``setjmp()`` / ``longjmp()`` or their variants for -+internal long control transfers. One downside of these functions is that -+C++ automatic destructors (scope-based resource management, SBRM, a special -+case of RAII) in Duktape/C functions won't be executed which is awkward for -+C++ programmers. -+ -+When ``DUK_USE_CPP_EXCEPTIONS`` is defined, and both Duktape and application -+code is compiled using a C++ compiler, Duktape uses C++ ``try-catch`` and -+``throw`` for internal long control transfers. This allows automatic -+destructors to run as expected. The config option is not enabled by default -+because C++ exceptions are sometimes disabled even when a C++ compiler is -+used (e.g. for performance reasons). -+ -+The ``cpp_exceptions.cpp`` example illustrates how C++ exceptions can be -+used in Duktape/C functions at the moment: -+ -+* Duktape uses C++ try/catch/throw internally; this is not visible to user -+ code directly. -+ -+* Automatic destructors (scope-based resource management) work as expected. -+ -+* C++ exceptions can be used in Duktape/C functions normally, but user -+ exceptions must be caught before they reach Duktape. If this is not -+ done, such exceptions are caught by Duktape and converted to API errors -+ (in other words, they won't propagate "through" Duktape at the moment). -diff --git a/dist/source/examples/cpp-exceptions/cpp_exceptions.cpp b/dist/source/examples/cpp-exceptions/cpp_exceptions.cpp -new file mode 100644 -index 0000000..67faf90 ---- /dev/null -+++ b/dist/source/examples/cpp-exceptions/cpp_exceptions.cpp -@@ -0,0 +1,311 @@ -+/* -+ * Example of how to use DUK_USE_CPP_EXCEPTIONS to support automatic -+ * variables (e.g. destructor calls) in Duktape/C functions. -+ * -+ * Configure and compile with -DDUK_USE_CPP_EXCEPTIONS: -+ * -+ * $ python2 tools/configure.py \ -+ * --source-directory src-input \ -+ * --output-directory /tmp/output \ -+ * --config-metadata config \ -+ * -DDUK_USE_CPP_EXCEPTIONS -+ * -+ * $ g++ -otest -I/tmp/output \ -+ * /tmp/output/duktape.c cpp_exceptions.cpp -lm -+ * -+ * When executed you should see something like: -+ * -+ * $ ./test -+ * my_class instance created -+ * my_class instance destroyed <== destructor gets called -+ * --> rc=1 (SyntaxError: parse error (line 1)) -+ * [...] -+ * -+ * Duktape uses a custom exception class (duk_internal_exception) which -+ * doesn't inherit from any base class, so that catching any base classes -+ * in user code won't accidentally catch exceptions thrown by Duktape. -+ */ -+ -+#if !defined(__cplusplus) -+#error compile using a c++ compiler -+#endif -+ -+#include -+#include -+#include "duktape.h" -+ -+#if defined(__cplusplus) && (__cplusplus >= 201103L) -+#define NOEXCEPT noexcept -+#else -+#define NOEXCEPT throw() -+#endif -+ -+/* -+ * Example class with a destructor -+ */ -+ -+class my_class { -+ public: -+ my_class(); -+ ~my_class(); -+}; -+ -+my_class::my_class() { -+ printf("my_class instance created\n"); -+} -+ -+my_class::~my_class() { -+ printf("my_class instance destroyed\n"); -+} -+ -+/* -+ * SyntaxError caused by eval exits Duktape/C function but destructors -+ * are executed. -+ */ -+ -+duk_ret_t test1(duk_context *ctx) { -+ my_class myclass; -+ -+ duk_eval_string(ctx, "aiee="); -+ -+ return 0; -+} -+duk_ret_t test1_safecall(duk_context *ctx, void *udata) { -+ (void) udata; -+ return test1(ctx); -+} -+ -+/* -+ * You can use C++ exceptions inside Duktape/C functions for your own -+ * purposes but you should catch them before they propagate to Duktape. -+ */ -+ -+duk_ret_t test2(duk_context *ctx) { -+ my_class myclass; -+ -+ try { -+ throw 123; -+ } catch (int myvalue) { -+ printf("Caught: %d\n", myvalue); -+ } -+ -+ return 0; -+} -+duk_ret_t test2_safecall(duk_context *ctx, void *udata) { -+ (void) udata; -+ return test2(ctx); -+} -+ -+/* -+ * If you let your own C++ exceptions propagate out of a Duktape/C function -+ * it will be caught by Duktape and considered a programming error. Duktape -+ * will catch the exception and convert it to a Duktape error. -+ * -+ * This may be allowed in a later version once all the implications have been -+ * worked out. -+ */ -+ -+duk_ret_t test3(duk_context *ctx) { -+ my_class myclass; -+ -+ throw 123; /* ERROR: exception propagated to Duktape */ -+ -+ return 0; -+} -+duk_ret_t test3_safecall(duk_context *ctx, void *udata) { -+ (void) udata; -+ return test3(ctx); -+} -+ -+/* -+ * Same as above, but if the exception inherits from std::exception, it's -+ * "what()" will be included in the error message. -+ */ -+ -+class my_exception : public std::exception { -+ virtual const char *what() const NOEXCEPT { -+ return "my_exception"; -+ } -+}; -+ -+duk_ret_t test4(duk_context *ctx) { -+ my_class myclass; -+ my_exception myexc; -+ -+ throw myexc; /* ERROR: exception propagated to Duktape */ -+ -+ return 0; -+} -+duk_ret_t test4_safecall(duk_context *ctx, void *udata) { -+ (void) udata; -+ return test4(ctx); -+} -+ -+/* -+ * Same as above, but if the exception inherits from std::exception with -+ * a NULL what(). Duktape will describe the error as 'unknown' if so. -+ */ -+ -+class my_exception2 : public std::exception { -+ virtual const char *what() const NOEXCEPT { -+ return NULL; -+ } -+}; -+ -+duk_ret_t test5(duk_context *ctx) { -+ my_class myclass; -+ my_exception2 myexc; -+ -+ throw myexc; /* ERROR: exception propagated to Duktape */ -+ -+ return 0; -+} -+duk_ret_t test5_safecall(duk_context *ctx, void *udata) { -+ (void) udata; -+ return test5(ctx); -+} -+ -+static duk_ret_t duk__print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ return 0; -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx = duk_create_heap_default(); -+ duk_int_t rc; -+ -+ (void) argc; (void) argv; /* suppress warning */ -+ -+ /* Minimal print() provider. */ -+ duk_push_c_function(ctx, duk__print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ -+ printf("*** test1 - duk_pcall()\n"); -+ duk_push_c_function(ctx, test1, 0); -+ rc = duk_pcall(ctx, 0); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test1 - duk_safe_call()\n"); -+ rc = duk_safe_call(ctx, test1_safecall, NULL, 0, 1); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test1 - ecmascript try-catch\n"); -+ duk_push_c_function(ctx, test1, 0); -+ duk_put_global_string(ctx, "test1"); -+ duk_eval_string_noresult(ctx, -+ "try {\n" -+ " test1();\n" -+ "} catch (e) {\n" -+ " print(e.stack || e);\n" -+ "}\n"); -+ printf("\n"); -+ -+ printf("*** test2 - duk_pcall()\n"); -+ duk_push_c_function(ctx, test2, 0); -+ rc = duk_pcall(ctx, 0); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test2 - duk_safe_call()\n"); -+ rc = duk_safe_call(ctx, test2_safecall, NULL, 0, 1); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test2 - ecmascript try-catch\n"); -+ duk_push_c_function(ctx, test2, 0); -+ duk_put_global_string(ctx, "test2"); -+ duk_eval_string_noresult(ctx, -+ "try {\n" -+ " test2();\n" -+ "} catch (e) {\n" -+ " print(e.stack || e);\n" -+ "}\n"); -+ printf("\n"); -+ -+ printf("*** test3 - duk_pcall()\n"); -+ duk_push_c_function(ctx, test3, 0); -+ rc = duk_pcall(ctx, 0); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test3 - duk_safe_call()\n"); -+ rc = duk_safe_call(ctx, test3_safecall, NULL, 0, 1); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test3 - ecmascript try-catch\n"); -+ duk_push_c_function(ctx, test3, 0); -+ duk_put_global_string(ctx, "test3"); -+ duk_eval_string_noresult(ctx, -+ "try {\n" -+ " test3();\n" -+ "} catch (e) {\n" -+ " print(e.stack || e);\n" -+ "}\n"); -+ printf("\n"); -+ -+ printf("*** test4 - duk_pcall()\n"); -+ duk_push_c_function(ctx, test4, 0); -+ rc = duk_pcall(ctx, 0); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test4 - duk_safe_call()\n"); -+ rc = duk_safe_call(ctx, test4_safecall, NULL, 0, 1); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test4 - ecmascript try-catch\n"); -+ duk_push_c_function(ctx, test4, 0); -+ duk_put_global_string(ctx, "test4"); -+ duk_eval_string_noresult(ctx, -+ "try {\n" -+ " test4();\n" -+ "} catch (e) {\n" -+ " print(e.stack || e);\n" -+ "}\n"); -+ printf("\n"); -+ -+ printf("*** test5 - duk_pcall()\n"); -+ duk_push_c_function(ctx, test5, 0); -+ rc = duk_pcall(ctx, 0); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test5 - duk_safe_call()\n"); -+ rc = duk_safe_call(ctx, test5_safecall, NULL, 0, 1); -+ printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ printf("\n"); -+ -+ printf("*** test5 - ecmascript try-catch\n"); -+ duk_push_c_function(ctx, test5, 0); -+ duk_put_global_string(ctx, "test5"); -+ duk_eval_string_noresult(ctx, -+ "try {\n" -+ " test5();\n" -+ "} catch (e) {\n" -+ " print(e.stack || e);\n" -+ "}\n"); -+ printf("\n"); -+ -+ printf("*** done\n"); -+ -+ duk_destroy_heap(ctx); -+ -+ return 0; -+} -diff --git a/dist/source/examples/debug-trans-dvalue/Makefile b/dist/source/examples/debug-trans-dvalue/Makefile -new file mode 100644 -index 0000000..79b7317 ---- /dev/null -+++ b/dist/source/examples/debug-trans-dvalue/Makefile -@@ -0,0 +1,16 @@ -+DUKTAPE_OPTS= -+DUKTAPE_OPTS+=-DDUK_USE_ASSERTIONS -+DUKTAPE_OPTS+=-DDUK_USE_DEBUGGER_SUPPORT -DDUK_USE_INTERRUPT_COUNTER -+DUKTAPE_OPTS+=-DDUK_USE_DEBUGGER_DUMPHEAP -+#DUKTAPE_OPTS+=-DDUK_USE_DEBUGGER_TRANSPORT_TORTURE -+TRANS_OPTS= -+#TRANS_OPTS+=-DDEBUG_PRINTS -+ -+test: test.c duk_trans_dvalue.c duk_trans_dvalue.h -+ rm -rf ./prep -+ python2 ../../tools/configure.py \ -+ --output-directory ./prep \ -+ $(DUKTAPE_OPTS) -+ gcc -O0 -g -ggdb -Wall -Wextra -std=c99 -o test -I./prep -I. \ -+ $(TRANS_OPTS) \ -+ ./prep/duktape.c duk_trans_dvalue.c test.c -lm -diff --git a/dist/source/examples/debug-trans-dvalue/README.rst b/dist/source/examples/debug-trans-dvalue/README.rst -new file mode 100644 -index 0000000..86b2bb5 ---- /dev/null -+++ b/dist/source/examples/debug-trans-dvalue/README.rst -@@ -0,0 +1,8 @@ -+=========================================================== -+Debug transport with local debug protocol encoding/decoding -+=========================================================== -+ -+This example implements a debug transport which decodes/encodes the Duktape -+debug protocol locally into a more easy to use C interface, which is useful -+for debug clients implemented locally on the target. The example also -+demonstrates how to trial parse dvalues in C. -diff --git a/dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.c b/dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.c -new file mode 100644 -index 0000000..84cf70b ---- /dev/null -+++ b/dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.c -@@ -0,0 +1,1241 @@ -+/* -+ * Example debug transport with a local debug message encoder/decoder. -+ * -+ * Provides a "received dvalue" callback for a fully parsed dvalue (user -+ * code frees dvalue) and a "cooperate" callback for e.g. UI integration. -+ * There are a few other callbacks. See test.c for usage examples. -+ * -+ * This transport implementation is not multithreaded which means that: -+ * -+ * - Callbacks to "received dvalue" callback come from the Duktape thread, -+ * either during normal execution or from duk_debugger_cooperate(). -+ * -+ * - Calls into duk_trans_dvalue_send() must be made from the callbacks -+ * provided (e.g. "received dvalue" or "cooperate") which use the active -+ * Duktape thread. -+ * -+ * - The only exception to this is when Duktape is idle: you can then call -+ * duk_trans_dvalue_send() from any thread (only one thread at a time). -+ * When you next call into Duktape or call duk_debugger_cooperate(), the -+ * queued data will be read and processed by Duktape. -+ * -+ * There are functions for creating and freeing values; internally they use -+ * malloc() and free() for memory management. Duktape heap alloc functions -+ * are not used to minimize disturbances to the Duktape heap under debugging. -+ * -+ * Doesn't depend on C99 types; assumes "int" is at least 32 bits, and makes -+ * a few assumptions about format specifiers. -+ */ -+ -+#include -+#include -+#include -+ -+#include "duktape.h" -+#include "duk_trans_dvalue.h" -+ -+/* Define to enable debug prints to stderr. */ -+#if 0 -+#define DEBUG_PRINTS -+#endif -+ -+/* Define to enable error prints to stderr. */ -+#if 1 -+#define ERROR_PRINTS -+#endif -+ -+/* -+ * Dvalue handling -+ */ -+ -+duk_dvalue *duk_dvalue_alloc(void) { -+ duk_dvalue *dv = (duk_dvalue *) malloc(sizeof(duk_dvalue)); -+ if (dv) { -+ memset((void *) dv, 0, sizeof(duk_dvalue)); -+ dv->buf = NULL; -+ } -+ return dv; -+} -+ -+void duk_dvalue_free(duk_dvalue *dv) { -+ if (dv) { -+ free(dv->buf); /* tolerates NULL */ -+ dv->buf = NULL; -+ free(dv); -+ } -+} -+ -+static void duk__dvalue_bufesc(duk_dvalue *dv, char *buf, size_t maxbytes, int stresc) { -+ size_t i, limit; -+ -+ *buf = (char) 0; -+ limit = dv->len > maxbytes ? maxbytes : dv->len; -+ for (i = 0; i < limit; i++) { -+ unsigned char c = dv->buf[i]; -+ if (stresc) { -+ if (c >= 0x20 && c <= 0x7e && c != (char) '"' && c != (char) '\'') { -+ sprintf(buf, "%c", c); -+ buf++; -+ } else { -+ sprintf(buf, "\\x%02x", (unsigned int) c); -+ buf += 4; -+ } -+ } else { -+ sprintf(buf, "%02x", (unsigned int) c); -+ buf += 2; -+ } -+ } -+ if (dv->len > maxbytes) { -+ sprintf(buf, "..."); -+ buf += 3; -+ } -+} -+ -+/* Caller must provide a buffer at least DUK_DVALUE_TOSTRING_BUFLEN in size. */ -+void duk_dvalue_to_string(duk_dvalue *dv, char *buf) { -+ char hexbuf[32 * 4 + 4]; /* 32 hex encoded or \xXX escaped bytes, possible "...", NUL */ -+ -+ if (!dv) { -+ sprintf(buf, "NULL"); -+ return; -+ } -+ -+ switch (dv->tag) { -+ case DUK_DVALUE_EOM: -+ sprintf(buf, "EOM"); -+ break; -+ case DUK_DVALUE_REQ: -+ sprintf(buf, "REQ"); -+ break; -+ case DUK_DVALUE_REP: -+ sprintf(buf, "REP"); -+ break; -+ case DUK_DVALUE_ERR: -+ sprintf(buf, "ERR"); -+ break; -+ case DUK_DVALUE_NFY: -+ sprintf(buf, "NFY"); -+ break; -+ case DUK_DVALUE_INTEGER: -+ sprintf(buf, "%d", dv->i); -+ break; -+ case DUK_DVALUE_STRING: -+ duk__dvalue_bufesc(dv, hexbuf, 32, 1); -+ sprintf(buf, "str:%ld:\"%s\"", (long) dv->len, hexbuf); -+ break; -+ case DUK_DVALUE_BUFFER: -+ duk__dvalue_bufesc(dv, hexbuf, 32, 0); -+ sprintf(buf, "buf:%ld:%s", (long) dv->len, hexbuf); -+ break; -+ case DUK_DVALUE_UNUSED: -+ sprintf(buf, "undefined"); -+ break; -+ case DUK_DVALUE_UNDEFINED: -+ sprintf(buf, "undefined"); -+ break; -+ case DUK_DVALUE_NULL: -+ sprintf(buf, "null"); -+ break; -+ case DUK_DVALUE_TRUE: -+ sprintf(buf, "true"); -+ break; -+ case DUK_DVALUE_FALSE: -+ sprintf(buf, "false"); -+ break; -+ case DUK_DVALUE_NUMBER: -+ if (fpclassify(dv->d) == FP_ZERO) { -+ if (signbit(dv->d)) { -+ sprintf(buf, "-0"); -+ } else { -+ sprintf(buf, "0"); -+ } -+ } else { -+ sprintf(buf, "%lg", dv->d); -+ } -+ break; -+ case DUK_DVALUE_OBJECT: -+ duk__dvalue_bufesc(dv, hexbuf, 32, 0); -+ sprintf(buf, "obj:%d:%s", (int) dv->i, hexbuf); -+ break; -+ case DUK_DVALUE_POINTER: -+ duk__dvalue_bufesc(dv, hexbuf, 32, 0); -+ sprintf(buf, "ptr:%s", hexbuf); -+ break; -+ case DUK_DVALUE_LIGHTFUNC: -+ duk__dvalue_bufesc(dv, hexbuf, 32, 0); -+ sprintf(buf, "lfunc:%04x:%s", (unsigned int) dv->i, hexbuf); -+ break; -+ case DUK_DVALUE_HEAPPTR: -+ duk__dvalue_bufesc(dv, hexbuf, 32, 0); -+ sprintf(buf, "heapptr:%s", hexbuf); -+ break; -+ default: -+ sprintf(buf, "unknown:%d", (int) dv->tag); -+ } -+} -+ -+duk_dvalue *duk_dvalue_make_tag(int tag) { -+ duk_dvalue *dv = duk_dvalue_alloc(); -+ if (!dv) { return NULL; } -+ dv->tag = tag; -+ return dv; -+} -+ -+duk_dvalue *duk_dvalue_make_tag_int(int tag, int intval) { -+ duk_dvalue *dv = duk_dvalue_alloc(); -+ if (!dv) { return NULL; } -+ dv->tag = tag; -+ dv->i = intval; -+ return dv; -+} -+ -+duk_dvalue *duk_dvalue_make_tag_double(int tag, double dblval) { -+ duk_dvalue *dv = duk_dvalue_alloc(); -+ if (!dv) { return NULL; } -+ dv->tag = tag; -+ dv->d = dblval; -+ return dv; -+} -+ -+duk_dvalue *duk_dvalue_make_tag_data(int tag, const char *buf, size_t len) { -+ unsigned char *p; -+ duk_dvalue *dv = duk_dvalue_alloc(); -+ if (!dv) { return NULL; } -+ /* Alloc size is len + 1 so that a NUL terminator is always -+ * guaranteed which is convenient, e.g. you can printf() the -+ * value safely. -+ */ -+ p = (unsigned char *) malloc(len + 1); -+ if (!p) { -+ free(dv); -+ return NULL; -+ } -+ memcpy((void *) p, (const void *) buf, len); -+ p[len] = (unsigned char) 0; -+ dv->tag = tag; -+ dv->buf = p; -+ dv->len = len; -+ return dv; -+} -+ -+duk_dvalue *duk_dvalue_make_tag_int_data(int tag, int intval, const char *buf, size_t len) { -+ duk_dvalue *dv = duk_dvalue_make_tag_data(tag, buf, len); -+ if (!dv) { return NULL; } -+ dv->i = intval; -+ return dv; -+} -+ -+/* -+ * Dvalue transport handling -+ */ -+ -+static void duk__trans_dvalue_double_byteswap(duk_trans_dvalue_ctx *ctx, volatile unsigned char *p) { -+ unsigned char t; -+ -+ /* Portable IEEE double byteswap. Relies on runtime detection of -+ * host endianness. -+ */ -+ -+ if (ctx->double_byteorder == 0) { -+ /* little endian */ -+ t = p[0]; p[0] = p[7]; p[7] = t; -+ t = p[1]; p[1] = p[6]; p[6] = t; -+ t = p[2]; p[2] = p[5]; p[5] = t; -+ t = p[3]; p[3] = p[4]; p[4] = t; -+ } else if (ctx->double_byteorder == 1) { -+ /* big endian: ok as is */ -+ ; -+ } else { -+ /* mixed endian */ -+ t = p[0]; p[0] = p[3]; p[3] = t; -+ t = p[1]; p[1] = p[2]; p[2] = t; -+ t = p[4]; p[4] = p[7]; p[7] = t; -+ t = p[5]; p[5] = p[6]; p[6] = t; -+ } -+} -+ -+static unsigned int duk__trans_dvalue_parse_u32(duk_trans_dvalue_ctx *ctx, unsigned char *p) { -+ /* Integers are network endian, read back into host format in -+ * a portable manner. -+ */ -+ (void) ctx; -+ return (((unsigned int) p[0]) << 24) + -+ (((unsigned int) p[1]) << 16) + -+ (((unsigned int) p[2]) << 8) + -+ (((unsigned int) p[3]) << 0); -+} -+ -+static int duk__trans_dvalue_parse_i32(duk_trans_dvalue_ctx *ctx, unsigned char *p) { -+ /* Portable sign handling, doesn't assume 'int' is exactly 32 bits -+ * like a direct cast would. -+ */ -+ unsigned int tmp = duk__trans_dvalue_parse_u32(ctx, p); -+ if (tmp & 0x80000000UL) { -+ return -((int) ((tmp ^ 0xffffffffUL) + 1UL)); -+ } else { -+ return tmp; -+ } -+} -+ -+static unsigned int duk__trans_dvalue_parse_u16(duk_trans_dvalue_ctx *ctx, unsigned char *p) { -+ /* Integers are network endian, read back into host format. */ -+ (void) ctx; -+ return (((unsigned int) p[0]) << 8) + -+ (((unsigned int) p[1]) << 0); -+} -+ -+static double duk__trans_dvalue_parse_double(duk_trans_dvalue_ctx *ctx, unsigned char *p) { -+ /* IEEE doubles are network endian, read back into host format. */ -+ volatile union { -+ double d; -+ unsigned char b[8]; -+ } u; -+ memcpy((void *) u.b, (const void *) p, 8); -+ duk__trans_dvalue_double_byteswap(ctx, u.b); -+ return u.d; -+} -+ -+static unsigned char *duk__trans_dvalue_encode_u32(duk_trans_dvalue_ctx *ctx, unsigned char *p, unsigned int val) { -+ /* Integers are written in network endian format. */ -+ (void) ctx; -+ *p++ = (unsigned char) ((val >> 24) & 0xff); -+ *p++ = (unsigned char) ((val >> 16) & 0xff); -+ *p++ = (unsigned char) ((val >> 8) & 0xff); -+ *p++ = (unsigned char) (val & 0xff); -+ return p; -+} -+ -+static unsigned char *duk__trans_dvalue_encode_i32(duk_trans_dvalue_ctx *ctx, unsigned char *p, int val) { -+ return duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) val & 0xffffffffUL); -+} -+ -+static unsigned char *duk__trans_dvalue_encode_u16(duk_trans_dvalue_ctx *ctx, unsigned char *p, unsigned int val) { -+ /* Integers are written in network endian format. */ -+ (void) ctx; -+ *p++ = (unsigned char) ((val >> 8) & 0xff); -+ *p++ = (unsigned char) (val & 0xff); -+ return p; -+} -+ -+static unsigned char *duk__trans_dvalue_encode_double(duk_trans_dvalue_ctx *ctx, unsigned char *p, double val) { -+ /* IEEE doubles are written in network endian format. */ -+ volatile union { -+ double d; -+ unsigned char b[8]; -+ } u; -+ u.d = val; -+ duk__trans_dvalue_double_byteswap(ctx, u.b); -+ memcpy((void *) p, (const void *) u.b, 8); -+ p += 8; -+ return p; -+} -+ -+static unsigned char *duk__trans_buffer_ensure(duk_trans_buffer *dbuf, size_t space) { -+ size_t avail; -+ size_t used; -+ size_t new_size; -+ void *new_alloc; -+ -+ used = dbuf->write_offset; -+ avail = dbuf->alloc_size - dbuf->write_offset; -+ -+ if (avail >= space) { -+ if (avail - space > 256) { -+ /* Too big, resize so that we reclaim memory if we have just -+ * received a large string/buffer value. -+ */ -+ goto do_realloc; -+ } -+ } else { -+ /* Too small, resize. */ -+ goto do_realloc; -+ } -+ -+ return dbuf->base + dbuf->write_offset; -+ -+ do_realloc: -+ new_size = used + space + 256; /* some extra to reduce resizes */ -+ new_alloc = realloc(dbuf->base, new_size); -+ if (new_alloc) { -+ dbuf->base = (unsigned char *) new_alloc; -+ dbuf->alloc_size = new_size; -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: resized buffer %p to %ld bytes, read_offset=%ld, write_offset=%ld\n", -+ __func__, (void *) dbuf, (long) new_size, (long) dbuf->read_offset, (long) dbuf->write_offset); -+ fflush(stderr); -+#endif -+ return dbuf->base + dbuf->write_offset; -+ } else { -+ return NULL; -+ } -+} -+ -+/* When read_offset is large enough, "rebase" buffer by deleting already -+ * read data and updating offsets. -+ */ -+static void duk__trans_buffer_rebase(duk_trans_buffer *dbuf) { -+ if (dbuf->read_offset > 64) { -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: rebasing buffer %p, read_offset=%ld, write_offset=%ld\n", -+ __func__, (void *) dbuf, (long) dbuf->read_offset, (long) dbuf->write_offset); -+ fflush(stderr); -+#endif -+ if (dbuf->write_offset > dbuf->read_offset) { -+ memmove((void *) dbuf->base, (const void *) (dbuf->base + dbuf->read_offset), dbuf->write_offset - dbuf->read_offset); -+ } -+ dbuf->write_offset -= dbuf->read_offset; -+ dbuf->read_offset = 0; -+ } -+} -+ -+duk_trans_dvalue_ctx *duk_trans_dvalue_init(void) { -+ volatile union { -+ double d; -+ unsigned char b[8]; -+ } u; -+ duk_trans_dvalue_ctx *ctx = NULL; -+ -+ ctx = (duk_trans_dvalue_ctx *) malloc(sizeof(duk_trans_dvalue_ctx)); -+ if (!ctx) { goto fail; } -+ memset((void *) ctx, 0, sizeof(duk_trans_dvalue_ctx)); -+ ctx->received = NULL; -+ ctx->cooperate = NULL; -+ ctx->handshake = NULL; -+ ctx->detached = NULL; -+ ctx->send_buf.base = NULL; -+ ctx->recv_buf.base = NULL; -+ -+ ctx->send_buf.base = malloc(256); -+ if (!ctx->send_buf.base) { goto fail; } -+ ctx->send_buf.alloc_size = 256; -+ -+ ctx->recv_buf.base = malloc(256); -+ if (!ctx->recv_buf.base) { goto fail; } -+ ctx->recv_buf.alloc_size = 256; -+ -+ /* IEEE double byte order, detect at run time (could also use -+ * preprocessor defines but that's verbose to make portable). -+ * -+ * >>> struct.unpack('>d', '1122334455667788'.decode('hex')) -+ * (3.841412024471731e-226,) -+ * >>> struct.unpack('>d', '8877665544332211'.decode('hex')) -+ * (-7.086876636573014e-268,) -+ * >>> struct.unpack('>d', '4433221188776655'.decode('hex')) -+ * (3.5294303071877444e+20,) -+ */ -+ u.b[0] = 0x11; u.b[1] = 0x22; u.b[2] = 0x33; u.b[3] = 0x44; -+ u.b[4] = 0x55; u.b[5] = 0x66; u.b[6] = 0x77; u.b[7] = 0x88; -+ if (u.d < 0.0) { -+ ctx->double_byteorder = 0; /* little endian */ -+ } else if (u.d < 1.0) { -+ ctx->double_byteorder = 1; /* big endian */ -+ } else { -+ ctx->double_byteorder = 2; /* mixed endian (arm) */ -+ } -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "double endianness test value is %lg -> byteorder %d\n", -+ u.d, ctx->double_byteorder); -+ fflush(stderr); -+#endif -+ -+ return ctx; -+ -+ fail: -+ if (ctx) { -+ free(ctx->recv_buf.base); /* tolerates NULL */ -+ free(ctx->send_buf.base); /* tolerates NULL */ -+ free(ctx); -+ } -+ return NULL; -+} -+ -+void duk_trans_dvalue_free(duk_trans_dvalue_ctx *ctx) { -+ if (ctx) { -+ free(ctx->send_buf.base); /* tolerates NULL */ -+ free(ctx->recv_buf.base); /* tolerates NULL */ -+ free(ctx); -+ } -+} -+ -+void duk_trans_dvalue_send(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) { -+ unsigned char *p; -+ -+ /* Convert argument dvalue into Duktape debug protocol format. -+ * Literal constants are used here for the debug protocol, -+ * e.g. initial byte 0x02 is REP, see doc/debugger.rst. -+ */ -+ -+#if defined(DEBUG_PRINTS) -+ { -+ char buf[DUK_DVALUE_TOSTRING_BUFLEN]; -+ duk_dvalue_to_string(dv, buf); -+ fprintf(stderr, "%s: sending dvalue: %s\n", __func__, buf); -+ fflush(stderr); -+ } -+#endif -+ -+ switch (dv->tag) { -+ case DUK_DVALUE_EOM: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x00; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_REQ: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x01; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_REP: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x02; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_ERR: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x03; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_NFY: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x04; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_INTEGER: { -+ int i = dv->i; -+ if (i >= 0 && i <= 63) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = (unsigned char) (0x80 + i); -+ ctx->send_buf.write_offset += 1; -+ } else if (i >= 0 && i <= 16383L) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 2); -+ if (!p) { goto alloc_error; } -+ *p++ = (unsigned char) (0xc0 + (i >> 8)); -+ *p++ = (unsigned char) (i & 0xff); -+ ctx->send_buf.write_offset += 2; -+ } else if (i >= -0x80000000L && i <= 0x7fffffffL) { /* Harmless warning on some platforms (re: range) */ -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 5); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x10; -+ p = duk__trans_dvalue_encode_i32(ctx, p, i); -+ ctx->send_buf.write_offset += 5; -+ } else { -+ goto dvalue_error; -+ } -+ break; -+ } -+ case DUK_DVALUE_STRING: { -+ size_t i = dv->len; -+ if (i <= 0x1fUL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = (unsigned char) (0x60 + i); -+ memcpy((void *) p, (const void *) dv->buf, i); -+ p += i; -+ ctx->send_buf.write_offset += 1 + i; -+ } else if (i <= 0xffffUL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x12; -+ p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) i); -+ memcpy((void *) p, (const void *) dv->buf, i); -+ p += i; -+ ctx->send_buf.write_offset += 3 + i; -+ } else if (i <= 0xffffffffUL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 5 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x11; -+ p = duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) i); -+ memcpy((void *) p, (const void *) dv->buf, i); -+ p += i; -+ ctx->send_buf.write_offset += 5 + i; -+ } else { -+ goto dvalue_error; -+ } -+ break; -+ } -+ case DUK_DVALUE_BUFFER: { -+ size_t i = dv->len; -+ if (i <= 0xffffUL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x14; -+ p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) i); -+ memcpy((void *) p, (const void *) dv->buf, i); -+ p += i; -+ ctx->send_buf.write_offset += 3 + i; -+ } else if (i <= 0xffffffffUL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 5 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x13; -+ p = duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) i); -+ memcpy((void *) p, (const void *) dv->buf, i); -+ p += i; -+ ctx->send_buf.write_offset += 5 + i; -+ } else { -+ goto dvalue_error; -+ } -+ break; -+ } -+ case DUK_DVALUE_UNUSED: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x15; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_UNDEFINED: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x16; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_NULL: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x17; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_TRUE: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x18; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_FALSE: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 1); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x19; -+ ctx->send_buf.write_offset += 1; -+ break; -+ } -+ case DUK_DVALUE_NUMBER: { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 9); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x1a; -+ p = duk__trans_dvalue_encode_double(ctx, p, dv->d); -+ ctx->send_buf.write_offset += 9; -+ break; -+ } -+ case DUK_DVALUE_OBJECT: { -+ size_t i = dv->len; -+ if (i <= 0xffUL && dv->i >= 0 && dv->i <= 0xffL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x1b; -+ *p++ = (unsigned char) dv->i; -+ *p++ = (unsigned char) i; -+ memcpy((void *) p, (const void *) dv->buf, i); -+ ctx->send_buf.write_offset += 3 + i; -+ } else { -+ goto dvalue_error; -+ } -+ break; -+ } -+ case DUK_DVALUE_POINTER: { -+ size_t i = dv->len; -+ if (i <= 0xffUL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 2 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x1c; -+ *p++ = (unsigned char) i; -+ memcpy((void *) p, (const void *) dv->buf, i); -+ ctx->send_buf.write_offset += 2 + i; -+ } else { -+ goto dvalue_error; -+ } -+ break; -+ } -+ case DUK_DVALUE_LIGHTFUNC: { -+ size_t i = dv->len; -+ if (i <= 0xffUL && dv->i >= 0 && dv->i <= 0xffffL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 4 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x1d; -+ p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) dv->i); -+ *p++ = (unsigned char) i; -+ memcpy((void *) p, (const void *) dv->buf, i); -+ ctx->send_buf.write_offset += 4 + i; -+ } else { -+ goto dvalue_error; -+ } -+ break; -+ } -+ case DUK_DVALUE_HEAPPTR: { -+ size_t i = dv->len; -+ if (i <= 0xffUL) { -+ p = duk__trans_buffer_ensure(&ctx->send_buf, 2 + i); -+ if (!p) { goto alloc_error; } -+ *p++ = 0x1e; -+ *p++ = (unsigned char) i; -+ memcpy((void *) p, (const void *) dv->buf, i); -+ ctx->send_buf.write_offset += 2 + i; -+ } else { -+ goto dvalue_error; -+ } -+ break; -+ } -+ default: { -+ goto dvalue_error; -+ } -+ } /* end switch */ -+ -+ return; -+ -+ dvalue_error: -+#if defined(ERROR_PRINTS) -+ fprintf(stderr, "%s: internal error, argument dvalue is invalid\n", __func__); -+ fflush(stdout); -+#endif -+ return; -+ -+ alloc_error: -+#if defined(ERROR_PRINTS) -+ fprintf(stderr, "%s: internal error, failed to allocate space for write\n", __func__); -+ fflush(stdout); -+#endif -+ return; -+} -+ -+static void duk__trans_dvalue_send_and_free(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) { -+ if (!dv) { return; } -+ duk_trans_dvalue_send(ctx, dv); -+ duk_dvalue_free(dv); -+} -+ -+void duk_trans_dvalue_send_eom(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_EOM)); -+} -+ -+void duk_trans_dvalue_send_req(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_REQ)); -+} -+ -+void duk_trans_dvalue_send_rep(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_REP)); -+} -+ -+void duk_trans_dvalue_send_err(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_ERR)); -+} -+ -+void duk_trans_dvalue_send_nfy(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_NFY)); -+} -+ -+void duk_trans_dvalue_send_integer(duk_trans_dvalue_ctx *ctx, int val) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, val)); -+} -+ -+void duk_trans_dvalue_send_string(duk_trans_dvalue_ctx *ctx, const char *str) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_STRING, str, strlen(str))); -+} -+ -+void duk_trans_dvalue_send_lstring(duk_trans_dvalue_ctx *ctx, const char *str, size_t len) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_STRING, str, len)); -+} -+ -+void duk_trans_dvalue_send_buffer(duk_trans_dvalue_ctx *ctx, const char *buf, size_t len) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, buf, len)); -+} -+ -+void duk_trans_dvalue_send_unused(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_UNUSED)); -+} -+ -+void duk_trans_dvalue_send_undefined(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_UNDEFINED)); -+} -+ -+void duk_trans_dvalue_send_null(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_NULL)); -+} -+ -+void duk_trans_dvalue_send_true(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_TRUE)); -+} -+ -+void duk_trans_dvalue_send_false(duk_trans_dvalue_ctx *ctx) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_FALSE)); -+} -+ -+void duk_trans_dvalue_send_number(duk_trans_dvalue_ctx *ctx, double val) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_double(DUK_DVALUE_NUMBER, val)); -+} -+ -+void duk_trans_dvalue_send_object(duk_trans_dvalue_ctx *ctx, int classnum, const char *ptr_data, size_t ptr_len) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int_data(DUK_DVALUE_OBJECT, classnum, ptr_data, ptr_len)); -+} -+ -+void duk_trans_dvalue_send_pointer(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_POINTER, ptr_data, ptr_len)); -+} -+ -+void duk_trans_dvalue_send_lightfunc(duk_trans_dvalue_ctx *ctx, int lf_flags, const char *ptr_data, size_t ptr_len) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int_data(DUK_DVALUE_LIGHTFUNC, lf_flags, ptr_data, ptr_len)); -+} -+ -+void duk_trans_dvalue_send_heapptr(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len) { -+ duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_HEAPPTR, ptr_data, ptr_len)); -+} -+ -+void duk_trans_dvalue_send_req_cmd(duk_trans_dvalue_ctx *ctx, int cmd) { -+ duk_trans_dvalue_send_req(ctx); -+ duk_trans_dvalue_send_integer(ctx, cmd); -+} -+ -+static duk_dvalue *duk__trans_trial_parse_dvalue(duk_trans_dvalue_ctx *ctx) { -+ unsigned char *p; -+ size_t len; -+ unsigned char ib; -+ duk_dvalue *dv; -+ size_t datalen; -+ -+ p = ctx->recv_buf.base + ctx->recv_buf.read_offset; -+ len = ctx->recv_buf.write_offset - ctx->recv_buf.read_offset; -+ -+ if (len == 0) { -+ return NULL; -+ } -+ ib = p[0]; -+ -+#if defined(DEBUG_PRINTS) -+ { -+ size_t i; -+ fprintf(stderr, "%s: parsing dvalue, window:", __func__); -+ for (i = 0; i < 16; i++) { -+ if (i < len) { -+ fprintf(stderr, " %02x", (unsigned int) p[i]); -+ } else { -+ fprintf(stderr, " ??"); -+ } -+ } -+ fprintf(stderr, " (length %ld, read_offset %ld, write_offset %ld, alloc_size %ld)\n", -+ (long) len, (long) ctx->recv_buf.read_offset, (long) ctx->recv_buf.write_offset, -+ (long) ctx->recv_buf.alloc_size); -+ fflush(stderr); -+ } -+#endif -+ -+ if (ib <= 0x1fU) { -+ /* 0x00 ... 0x1f */ -+ switch (ib) { -+ case 0x00: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_EOM); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x01: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_REQ); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x02: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_REP); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x03: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_ERR); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x04: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_NFY); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x10: { -+ int intval; -+ if (len < 5) { goto partial; } -+ intval = duk__trans_dvalue_parse_i32(ctx, p + 1); -+ ctx->recv_buf.read_offset += 5; -+ dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x11: { -+ if (len < 5) { goto partial; } -+ datalen = (size_t) duk__trans_dvalue_parse_u32(ctx, p + 1); -+ if (len < 5 + datalen) { goto partial; } -+ ctx->recv_buf.read_offset += 5 + datalen; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 5), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x12: { -+ if (len < 3) { goto partial; } -+ datalen = (size_t) duk__trans_dvalue_parse_u16(ctx, p + 1); -+ if (len < 3 + datalen) { goto partial; } -+ ctx->recv_buf.read_offset += 3 + datalen; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 3), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x13: { -+ if (len < 5) { goto partial; } -+ datalen = (size_t) duk__trans_dvalue_parse_u32(ctx, p + 1); -+ if (len < 5 + datalen) { goto partial; } -+ ctx->recv_buf.read_offset += 5 + datalen; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, (const char *) (p + 5), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x14: { -+ if (len < 3) { goto partial; } -+ datalen = (size_t) duk__trans_dvalue_parse_u16(ctx, p + 1); -+ if (len < 3 + datalen) { goto partial; } -+ ctx->recv_buf.read_offset += 3 + datalen; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, (const char *) (p + 3), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x15: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_UNUSED); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x16: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_UNDEFINED); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x17: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_NULL); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x18: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_TRUE); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x19: { -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag(DUK_DVALUE_FALSE); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x1a: { -+ double dblval; -+ if (len < 9) { goto partial; } -+ dblval = duk__trans_dvalue_parse_double(ctx, p + 1); -+ ctx->recv_buf.read_offset += 9; -+ dv = duk_dvalue_make_tag_double(DUK_DVALUE_NUMBER, dblval); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x1b: { -+ int classnum; -+ if (len < 3) { goto partial; } -+ datalen = (size_t) p[2]; -+ if (len < 3 + datalen) { goto partial; } -+ classnum = (int) p[1]; -+ ctx->recv_buf.read_offset += 3 + datalen; -+ dv = duk_dvalue_make_tag_int_data(DUK_DVALUE_OBJECT, classnum, (const char *) (p + 3), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x1c: { -+ if (len < 2) { goto partial; } -+ datalen = (size_t) p[1]; -+ if (len < 2 + datalen) { goto partial; } -+ ctx->recv_buf.read_offset += 2 + datalen; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_POINTER, (const char *) (p + 2), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x1d: { -+ int lf_flags; -+ if (len < 4) { goto partial; } -+ datalen = (size_t) p[3]; -+ if (len < 4 + datalen) { goto partial; } -+ lf_flags = (int) duk__trans_dvalue_parse_u16(ctx, p + 1); -+ ctx->recv_buf.read_offset += 4 + datalen; -+ dv = duk_dvalue_make_tag_int_data(DUK_DVALUE_LIGHTFUNC, lf_flags, (const char *) (p + 4), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ case 0x1e: { -+ if (len < 2) { goto partial; } -+ datalen = (size_t) p[1]; -+ if (len < 2 + datalen) { goto partial; } -+ ctx->recv_buf.read_offset += 2 + datalen; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_HEAPPTR, (const char *) (p + 2), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ default: { -+ goto format_error; -+ } -+ } /* end switch */ -+ } else if (ib <= 0x5fU) { -+ /* 0x20 ... 0x5f */ -+ goto format_error; -+ } else if (ib <= 0x7fU) { -+ /* 0x60 ... 0x7f */ -+ datalen = (size_t) (ib - 0x60U); -+ if (len < 1 + datalen) { goto partial; } -+ ctx->recv_buf.read_offset += 1 + datalen; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 1), datalen); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } else if (ib <= 0xbfU) { -+ /* 0x80 ... 0xbf */ -+ int intval; -+ intval = (int) (ib - 0x80U); -+ ctx->recv_buf.read_offset += 1; -+ dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } else { -+ /* 0xc0 ... 0xff */ -+ int intval; -+ if (len < 2) { goto partial; } -+ intval = (((int) (ib - 0xc0U)) << 8) + (int) p[1]; -+ ctx->recv_buf.read_offset += 2; -+ dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ -+ /* never here */ -+ -+ partial: -+ return NULL; -+ -+ alloc_error: -+#if defined(ERROR_PRINTS) -+ fprintf(stderr, "%s: internal error, cannot allocate space for dvalue\n", __func__); -+ fflush(stdout); -+#endif -+ return NULL; -+ -+ format_error: -+#if defined(ERROR_PRINTS) -+ fprintf(stderr, "%s: internal error, dvalue format error\n", __func__); -+ fflush(stdout); -+#endif -+ return NULL; -+} -+ -+static duk_dvalue *duk__trans_trial_parse_handshake(duk_trans_dvalue_ctx *ctx) { -+ unsigned char *p; -+ size_t len; -+ duk_dvalue *dv; -+ size_t i; -+ -+ p = ctx->recv_buf.base + ctx->recv_buf.read_offset; -+ len = ctx->recv_buf.write_offset - ctx->recv_buf.read_offset; -+ -+ for (i = 0; i < len; i++) { -+ if (p[i] == 0x0a) { -+ /* Handshake line is returned as a dvalue for convenience; it's -+ * not actually a part of the dvalue phase of the protocol. -+ */ -+ ctx->recv_buf.read_offset += i + 1; -+ dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) p, i); -+ if (!dv) { goto alloc_error; } -+ return dv; -+ } -+ } -+ -+ return NULL; -+ -+ alloc_error: -+#if defined(ERROR_PRINTS) -+ fprintf(stderr, "%s: internal error, cannot allocate space for handshake line\n", __func__); -+ fflush(stdout); -+#endif -+ return NULL; -+} -+ -+static void duk__trans_call_cooperate(duk_trans_dvalue_ctx *ctx, int block) { -+ if (ctx->cooperate) { -+ ctx->cooperate(ctx, block); -+ } -+} -+ -+static void duk__trans_call_received(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) { -+ if (ctx->received) { -+ ctx->received(ctx, dv); -+ } -+} -+ -+static void duk__trans_call_handshake(duk_trans_dvalue_ctx *ctx, const char *line) { -+ if (ctx->handshake) { -+ ctx->handshake(ctx, line); -+ } -+} -+ -+static void duk__trans_call_detached(duk_trans_dvalue_ctx *ctx) { -+ if (ctx->detached) { -+ ctx->detached(ctx); -+ } -+} -+ -+/* -+ * Duktape callbacks -+ */ -+ -+duk_size_t duk_trans_dvalue_read_cb(void *udata, char *buffer, duk_size_t length) { -+ duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata; -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: %p %p %ld\n", __func__, udata, (void *) buffer, (long) length); -+ fflush(stderr); -+#endif -+ -+ duk__trans_call_cooperate(ctx, 0); -+ -+ for (;;) { -+ size_t avail, now; -+ -+ avail = (size_t) (ctx->send_buf.write_offset - ctx->send_buf.read_offset); -+ if (avail == 0) { -+ /* Must cooperate until user callback provides data. From -+ * Duktape's perspective we MUST block until data is received. -+ */ -+ duk__trans_call_cooperate(ctx, 1); -+ } else { -+ now = avail; -+ if (now > length) { -+ now = length; -+ } -+ memcpy((void *) buffer, (const void *) (ctx->send_buf.base + ctx->send_buf.read_offset), now); -+ duk__trans_buffer_rebase(&ctx->send_buf); -+ ctx->send_buf.read_offset += now; -+ return now; -+ } -+ } -+} -+ -+duk_size_t duk_trans_dvalue_write_cb(void *udata, const char *buffer, duk_size_t length) { -+ duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata; -+ unsigned char *p; -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: %p %p %ld\n", __func__, udata, (void *) buffer, (long) length); -+ fflush(stderr); -+#endif -+ -+ duk__trans_call_cooperate(ctx, 0); -+ -+ /* Append data. */ -+ duk__trans_buffer_rebase(&ctx->recv_buf); -+ p = duk__trans_buffer_ensure(&ctx->recv_buf, length); -+ memcpy((void *) p, (const void *) buffer, (size_t) length); -+ ctx->recv_buf.write_offset += length; -+ -+ /* Trial parse handshake line or dvalue(s). */ -+ if (!ctx->handshake_done) { -+ duk_dvalue *dv = duk__trans_trial_parse_handshake(ctx); -+ if (dv) { -+ /* Handshake line is available for caller for the -+ * duration of the callback, and must not be freed -+ * by the caller. -+ */ -+ duk__trans_call_handshake(ctx, (const char *) dv->buf); -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: handshake ok\n", __func__); -+ fflush(stderr); -+#endif -+ duk_dvalue_free(dv); -+ ctx->handshake_done = 1; -+ } -+ } -+ if (ctx->handshake_done) { -+ for (;;) { -+ duk_dvalue *dv = duk__trans_trial_parse_dvalue(ctx); -+ if (dv) { -+#if defined(DEBUG_PRINTS) -+ { -+ char buf[DUK_DVALUE_TOSTRING_BUFLEN]; -+ duk_dvalue_to_string(dv, buf); -+ fprintf(stderr, "%s: received dvalue: %s\n", __func__, buf); -+ fflush(stderr); -+ } -+#endif -+ -+ duk__trans_call_received(ctx, dv); -+ } else { -+ break; -+ } -+ } -+ } -+ -+ duk__trans_call_cooperate(ctx, 0); /* just in case, if dvalues changed something */ -+ -+ return length; -+} -+ -+duk_size_t duk_trans_dvalue_peek_cb(void *udata) { -+ duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata; -+ size_t avail; -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: %p\n", __func__, udata); -+ fflush(stderr); -+#endif -+ -+ duk__trans_call_cooperate(ctx, 0); -+ avail = (size_t) (ctx->send_buf.write_offset - ctx->send_buf.read_offset); -+ return (duk_size_t) avail; -+} -+ -+void duk_trans_dvalue_read_flush_cb(void *udata) { -+ duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata; -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: %p\n", __func__, udata); -+ fflush(stderr); -+#endif -+ -+ duk__trans_call_cooperate(ctx, 0); -+} -+ -+void duk_trans_dvalue_write_flush_cb(void *udata) { -+ duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata; -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: %p\n", __func__, udata); -+ fflush(stderr); -+#endif -+ -+ duk__trans_call_cooperate(ctx, 0); -+} -+ -+void duk_trans_dvalue_detached_cb(duk_context *duk_ctx, void *udata) { -+ duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata; -+ -+ (void) duk_ctx; -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: %p\n", __func__, udata); -+ fflush(stderr); -+#endif -+ -+ duk__trans_call_detached(ctx); -+} -diff --git a/dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.h b/dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.h -new file mode 100644 -index 0000000..a9f44ed ---- /dev/null -+++ b/dist/source/examples/debug-trans-dvalue/duk_trans_dvalue.h -@@ -0,0 +1,113 @@ -+#if !defined(DUK_TRANS_DVALUE_H_INCLUDED) -+#define DUK_TRANS_DVALUE_H_INCLUDED -+ -+#include "duktape.h" -+ -+typedef struct duk_dvalue duk_dvalue; -+typedef struct duk_trans_buffer duk_trans_buffer; -+typedef struct duk_trans_dvalue_ctx duk_trans_dvalue_ctx; -+ -+typedef void (*duk_trans_dvalue_received_function)(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv); -+typedef void (*duk_trans_dvalue_cooperate_function)(duk_trans_dvalue_ctx *ctx, int block); -+typedef void (*duk_trans_dvalue_handshake_function)(duk_trans_dvalue_ctx *ctx, const char *handshake_line); -+typedef void (*duk_trans_dvalue_detached_function)(duk_trans_dvalue_ctx *ctx); -+ -+/* struct duk_dvalue 'tag' values, note that these have nothing to do with -+ * Duktape debug protocol inital byte. Struct fields used with the type -+ * are noted next to the define. -+ */ -+#define DUK_DVALUE_EOM 1 /* no fields */ -+#define DUK_DVALUE_REQ 2 /* no fields */ -+#define DUK_DVALUE_REP 3 /* no fields */ -+#define DUK_DVALUE_ERR 4 /* no fields */ -+#define DUK_DVALUE_NFY 5 /* no fields */ -+#define DUK_DVALUE_INTEGER 6 /* i: 32-bit signed integer */ -+#define DUK_DVALUE_STRING 7 /* buf: string data, len: string length */ -+#define DUK_DVALUE_BUFFER 8 /* buf: buffer data, len: buffer length */ -+#define DUK_DVALUE_UNUSED 9 /* no fields */ -+#define DUK_DVALUE_UNDEFINED 10 /* no fields */ -+#define DUK_DVALUE_NULL 11 /* no fields */ -+#define DUK_DVALUE_TRUE 12 /* no fields */ -+#define DUK_DVALUE_FALSE 13 /* no fields */ -+#define DUK_DVALUE_NUMBER 14 /* d: ieee double */ -+#define DUK_DVALUE_OBJECT 15 /* i: class number, buf: pointer data, len: pointer length */ -+#define DUK_DVALUE_POINTER 16 /* buf: pointer data, len: pointer length */ -+#define DUK_DVALUE_LIGHTFUNC 17 /* i: lightfunc flags, buf: pointer data, len: pointer length */ -+#define DUK_DVALUE_HEAPPTR 18 /* buf: pointer data, len: pointer length */ -+ -+struct duk_dvalue { -+ /* Could use a union for the value but the gain would be relatively small. */ -+ int tag; -+ int i; -+ double d; -+ size_t len; -+ unsigned char *buf; -+}; -+ -+struct duk_trans_buffer { -+ unsigned char *base; -+ size_t write_offset; -+ size_t read_offset; -+ size_t alloc_size; -+}; -+ -+struct duk_trans_dvalue_ctx { -+ duk_trans_dvalue_received_function received; -+ duk_trans_dvalue_cooperate_function cooperate; -+ duk_trans_dvalue_handshake_function handshake; -+ duk_trans_dvalue_detached_function detached; -+ duk_trans_buffer send_buf; /* sending towards Duktape (duktape read callback) */ -+ duk_trans_buffer recv_buf; /* receiving from Duktape (duktape write callback) */ -+ int handshake_done; -+ int double_byteorder; /* 0=little endian, 1=big endian, 2=mixed endian */ -+}; -+ -+/* Buffer size needed by duk_dvalue_to_string(). */ -+#define DUK_DVALUE_TOSTRING_BUFLEN 256 -+ -+/* Dvalue handling. */ -+duk_dvalue *duk_dvalue_alloc(void); -+void duk_dvalue_free(duk_dvalue *dv); -+void duk_dvalue_to_string(duk_dvalue *dv, char *buf); -+duk_dvalue *duk_dvalue_make_tag(int tag); -+duk_dvalue *duk_dvalue_make_tag_int(int tag, int intval); -+duk_dvalue *duk_dvalue_make_tag_double(int tag, double dblval); -+duk_dvalue *duk_dvalue_make_tag_data(int tag, const char *buf, size_t len); -+duk_dvalue *duk_dvalue_make_tag_int_data(int tag, int intval, const char *buf, size_t len); -+ -+/* Initializing and freeing the transport context. */ -+duk_trans_dvalue_ctx *duk_trans_dvalue_init(void); -+void duk_trans_dvalue_free(duk_trans_dvalue_ctx *ctx); -+ -+/* Sending dvalues towards Duktape. */ -+void duk_trans_dvalue_send(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv); -+void duk_trans_dvalue_send_eom(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_req(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_rep(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_err(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_nfy(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_integer(duk_trans_dvalue_ctx *ctx, int val); -+void duk_trans_dvalue_send_string(duk_trans_dvalue_ctx *ctx, const char *str); -+void duk_trans_dvalue_send_lstring(duk_trans_dvalue_ctx *ctx, const char *str, size_t len); -+void duk_trans_dvalue_send_buffer(duk_trans_dvalue_ctx *ctx, const char *buf, size_t len); -+void duk_trans_dvalue_send_unused(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_undefined(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_null(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_true(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_false(duk_trans_dvalue_ctx *ctx); -+void duk_trans_dvalue_send_number(duk_trans_dvalue_ctx *ctx, double val); -+void duk_trans_dvalue_send_object(duk_trans_dvalue_ctx *ctx, int classnum, const char *ptr_data, size_t ptr_len); -+void duk_trans_dvalue_send_pointer(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len); -+void duk_trans_dvalue_send_lightfunc(duk_trans_dvalue_ctx *ctx, int lf_flags, const char *ptr_data, size_t ptr_len); -+void duk_trans_dvalue_send_heapptr(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len); -+void duk_trans_dvalue_send_req_cmd(duk_trans_dvalue_ctx *ctx, int cmd); -+ -+/* Duktape debug callbacks provided by the transport. */ -+duk_size_t duk_trans_dvalue_read_cb(void *udata, char *buffer, duk_size_t length); -+duk_size_t duk_trans_dvalue_write_cb(void *udata, const char *buffer, duk_size_t length); -+duk_size_t duk_trans_dvalue_peek_cb(void *udata); -+void duk_trans_dvalue_read_flush_cb(void *udata); -+void duk_trans_dvalue_write_flush_cb(void *udata); -+void duk_trans_dvalue_detached_cb(duk_context *ctx, void *udata); -+ -+#endif /* DUK_TRANS_DVALUE_H_INCLUDED */ -diff --git a/dist/source/examples/debug-trans-dvalue/test.c b/dist/source/examples/debug-trans-dvalue/test.c -new file mode 100644 -index 0000000..80b35d7 ---- /dev/null -+++ b/dist/source/examples/debug-trans-dvalue/test.c -@@ -0,0 +1,248 @@ -+/* -+ * Example program using the dvalue debug transport. -+ */ -+ -+#include -+#include -+ -+#include "duktape.h" -+#include "duk_trans_dvalue.h" -+ -+void my_cooperate(duk_trans_dvalue_ctx *ctx, int block) { -+ static int first_blocked = 1; -+ -+ if (!block) { -+ /* Duktape is not blocked; you can cooperate with e.g. a user -+ * interface here and send dvalues to Duktape, but don't block. -+ */ -+ return; -+ } -+ -+ /* Duktape is blocked on a read and won't continue until debug -+ * command(s) are sent. -+ * -+ * Normally you'd enter your own event loop here, and process -+ * events until something needs to be sent to Duktape. For -+ * example, the user might press a "Step over" button in the -+ * UI which would cause dvalues to be sent. You can then -+ * return from this callback. -+ * -+ * The code below sends some example messages for testing the -+ * dvalue handling of the transport. -+ * -+ * If you create dvalues manually and send them using -+ * duk_trans_dvalue_send(), you must free the dvalues after -+ * the send call returns using duk_dvalue_free(). -+ */ -+ -+ if (first_blocked) { -+ char *tmp; -+ int i; -+ -+ /* First time Duktape becomes blocked, send DumpHeap which -+ * exercises a lot of parsing code. -+ * -+ * NOTE: Valgrind may complain about reading uninitialized -+ * bytes. This is caused by the DumpHeap command writing out -+ * verbatim duk_tval values which are intentionally not -+ * always fully initialized for performance reasons. -+ */ -+ first_blocked = 0; -+ -+ fprintf(stderr, "Duktape is blocked, send DumpHeap\n"); -+ fflush(stderr); -+ -+ duk_trans_dvalue_send_req(ctx); -+ duk_trans_dvalue_send_integer(ctx, 0x20); /* DumpHeap */ -+ duk_trans_dvalue_send_eom(ctx); -+ -+ /* Also send a dummy TriggerStatus request with trailing dvalues -+ * ignored by Duktape; Duktape will parse the dvalues to be able to -+ * skip them, so that the dvalue encoding is exercised. -+ */ -+ -+ tmp = malloc(100000); /* long buffer, >= 65536 chars */ -+ for (i = 0; i < 100000; i++) { -+ tmp[i] = (char) i; -+ } -+ duk_trans_dvalue_send_req(ctx); -+ duk_trans_dvalue_send_integer(ctx, 0x11); /* TriggerStatus */ -+ duk_trans_dvalue_send_string(ctx, "dummy"); /* short, <= 31 chars */ -+ duk_trans_dvalue_send_string(ctx, "123456789012345678901234567890foobar"); /* medium, >= 32 chars */ -+ duk_trans_dvalue_send_lstring(ctx, (const char *) tmp, 65535UL); -+ duk_trans_dvalue_send_lstring(ctx, (const char *) tmp, 65536UL); -+ duk_trans_dvalue_send_lstring(ctx, (const char *) tmp, 100000UL); -+ duk_trans_dvalue_send_buffer(ctx, (const char *) tmp, 255U); -+ duk_trans_dvalue_send_buffer(ctx, (const char *) tmp, 65535UL); -+ duk_trans_dvalue_send_buffer(ctx, (const char *) tmp, 65536UL); -+ duk_trans_dvalue_send_buffer(ctx, (const char *) tmp, 100000UL); -+ duk_trans_dvalue_send_unused(ctx); -+ duk_trans_dvalue_send_undefined(ctx); -+ duk_trans_dvalue_send_null(ctx); -+ duk_trans_dvalue_send_true(ctx); -+ duk_trans_dvalue_send_false(ctx); -+ duk_trans_dvalue_send_number(ctx, 123.456); -+ duk_trans_dvalue_send_object(ctx, 12 /*classnum*/, (const char *) tmp, 8); /* fake ptr len */ -+ duk_trans_dvalue_send_pointer(ctx, (const char *) tmp, 8); /* fake ptr len */ -+ duk_trans_dvalue_send_lightfunc(ctx, 0xdabc /*lf_flags*/, (const char *) tmp, 8); /* fake ptr len */ -+ duk_trans_dvalue_send_heapptr(ctx, (const char *) tmp, 8); /* fake ptr len */ -+ -+ duk_trans_dvalue_send_eom(ctx); -+ } -+ -+ fprintf(stderr, "Duktape is blocked, send Eval and StepInto to resume execution\n"); -+ fflush(stderr); -+ -+ /* duk_trans_dvalue_send_req_cmd() sends a REQ dvalue followed by -+ * an integer dvalue (command) for convenience. -+ */ -+ -+ duk_trans_dvalue_send_req_cmd(ctx, 0x1e); /* 0x1e = Eval */ -+ duk_trans_dvalue_send_string(ctx, "evalMe"); -+ duk_trans_dvalue_send_eom(ctx); -+ -+ duk_trans_dvalue_send_req_cmd(ctx, 0x14); /* 0x14 = StepOver */ -+ duk_trans_dvalue_send_eom(ctx); -+} -+ -+void my_received(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) { -+ char buf[DUK_DVALUE_TOSTRING_BUFLEN]; -+ (void) ctx; -+ -+ duk_dvalue_to_string(dv, buf); -+ fprintf(stderr, "Received dvalue: %s\n", buf); -+ fflush(stderr); -+ -+ /* Here a normal debug client would wait for dvalues until an EOM -+ * dvalue was received (which completes a debug message). The -+ * debug message would then be handled, possibly causing UI changes -+ * and/or causing debug commands to be sent to Duktape. -+ * -+ * The callback is responsible for eventually freeing the dvalue. -+ * Here we free it immediately, but an actual client would probably -+ * gather dvalues into an array or linked list to handle when the -+ * debug message was complete. -+ */ -+ -+ duk_dvalue_free(dv); -+} -+ -+void my_handshake(duk_trans_dvalue_ctx *ctx, const char *line) { -+ (void) ctx; -+ -+ /* The Duktape handshake line is given in 'line' (without LF). -+ * The 'line' argument can be accessed for the duration of the -+ * callback (read only). Don't free 'line' here, the transport -+ * handles that. -+ */ -+ -+ fprintf(stderr, "Received handshake line: '%s'\n", line); -+ fflush(stderr); -+} -+ -+void my_detached(duk_trans_dvalue_ctx *ctx) { -+ (void) ctx; -+ -+ /* Detached call forwarded as is. */ -+ -+ fprintf(stderr, "Debug transport detached\n"); -+ fflush(stderr); -+} -+ -+static duk_ret_t native_print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_to_string(ctx, -1)); -+ return 0; -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ duk_trans_dvalue_ctx *trans_ctx; -+ int exitval = 0; -+ -+ (void) argc; (void) argv; /* suppress warning */ -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { -+ fprintf(stderr, "Failed to create Duktape heap\n"); -+ fflush(stderr); -+ exitval = 1; -+ goto cleanup; -+ } -+ -+ duk_push_c_function(ctx, native_print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ -+ trans_ctx = duk_trans_dvalue_init(); -+ if (!trans_ctx) { -+ fprintf(stderr, "Failed to create debug transport context\n"); -+ fflush(stderr); -+ exitval = 1; -+ goto cleanup; -+ } -+ trans_ctx->cooperate = my_cooperate; -+ trans_ctx->received = my_received; -+ trans_ctx->handshake = my_handshake; -+ trans_ctx->detached = my_detached; -+ -+ /* Attach debugger; this will fail with a fatal error here unless -+ * debugger support is compiled in. To fail more gracefully, call -+ * this under a duk_safe_call() to catch the error. -+ */ -+ duk_debugger_attach(ctx, -+ duk_trans_dvalue_read_cb, -+ duk_trans_dvalue_write_cb, -+ duk_trans_dvalue_peek_cb, -+ duk_trans_dvalue_read_flush_cb, -+ duk_trans_dvalue_write_flush_cb, -+ NULL, /* app request cb */ -+ duk_trans_dvalue_detached_cb, -+ (void *) trans_ctx); -+ -+ fprintf(stderr, "Debugger attached, running eval\n"); -+ fflush(stderr); -+ -+ /* Evaluate simple test code, callbacks will "step over" until end. -+ * -+ * The test code here is just for exercising the debug transport. -+ * The 'evalMe' variable is evaluated (using debugger command Eval) -+ * before every step to force different dvalues to be carried over -+ * the transport. -+ */ -+ -+ duk_eval_string(ctx, -+ "var evalMe;\n" -+ "\n" -+ "print('Hello world!');\n" -+ "[ undefined, null, true, false, 123, -123, 123.1, 0, -0, 1/0, 0/0, -1/0, \n" -+ " 'foo', Uint8Array.allocPlain('bar'), Duktape.Pointer('dummy'), Math.cos, \n" -+ "].forEach(function (val) {\n" -+ " print(val);\n" -+ " evalMe = val;\n" -+ "});\n" -+ "\n" -+ "var str = 'xxx'\n" -+ "for (i = 0; i < 10; i++) {\n" -+ " print(i, str);\n" -+ " evalMe = str;\n" -+ " evalMe = Uint8Array.allocPlain(str);\n" -+ " str = str + str;\n" -+ "}\n" -+ ); -+ duk_pop(ctx); -+ -+ duk_debugger_detach(ctx); -+ -+ cleanup: -+ if (trans_ctx) { -+ duk_trans_dvalue_free(trans_ctx); -+ trans_ctx = NULL; -+ } -+ if (ctx) { -+ duk_destroy_heap(ctx); -+ } -+ -+ return exitval; -+} -diff --git a/dist/source/examples/debug-trans-socket/README.rst b/dist/source/examples/debug-trans-socket/README.rst -new file mode 100644 -index 0000000..78522cd ---- /dev/null -+++ b/dist/source/examples/debug-trans-socket/README.rst -@@ -0,0 +1,17 @@ -+================================================ -+Debug transport using a simple socket connection -+================================================ -+ -+This example implements an example debug transport which uses a Linux or -+Windows TCP server socket on the debug target. -+ -+Files: -+ -+* ``duk_trans_socket.h``: header file for the transport, used for both Linux -+ and Windows socket variants. -+ -+* ``duk_trans_socket_unix.c``: implementation for Linux/Unix. -+ -+* ``duk_trans_socket_windows.c``: implementation for Windows. -+ -+Compile either Unix or Windows source file only. -diff --git a/dist/source/examples/debug-trans-socket/duk_trans_socket.h b/dist/source/examples/debug-trans-socket/duk_trans_socket.h -new file mode 100644 -index 0000000..4671a1d ---- /dev/null -+++ b/dist/source/examples/debug-trans-socket/duk_trans_socket.h -@@ -0,0 +1,23 @@ -+#if !defined(DUK_TRANS_SOCKET_H_INCLUDED) -+#define DUK_TRANS_SOCKET_H_INCLUDED -+ -+#include "duktape.h" -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+void duk_trans_socket_init(void); -+void duk_trans_socket_finish(void); -+void duk_trans_socket_waitconn(void); -+duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length); -+duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length); -+duk_size_t duk_trans_socket_peek_cb(void *udata); -+void duk_trans_socket_read_flush_cb(void *udata); -+void duk_trans_socket_write_flush_cb(void *udata); -+ -+#if defined(__cplusplus) -+} -+#endif /* end 'extern "C"' wrapper */ -+ -+#endif /* DUK_TRANS_SOCKET_H_INCLUDED */ -diff --git a/dist/source/examples/debug-trans-socket/duk_trans_socket_unix.c b/dist/source/examples/debug-trans-socket/duk_trans_socket_unix.c -new file mode 100644 -index 0000000..0633eff ---- /dev/null -+++ b/dist/source/examples/debug-trans-socket/duk_trans_socket_unix.c -@@ -0,0 +1,364 @@ -+/* -+ * Example debug transport using a Linux/Unix TCP socket -+ * -+ * Provides a TCP server socket which a debug client can connect to. -+ * After that data is just passed through. -+ * -+ * On some UNIX systems poll() may not be available but select() is. -+ * The default is to use poll(), but you can switch to select() by -+ * defining USE_SELECT. See https://daniel.haxx.se/docs/poll-vs-select.html. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#if !defined(USE_SELECT) -+#include -+#endif /* !USE_SELECT */ -+#include -+#include "duktape.h" -+#include "duk_trans_socket.h" -+ -+#if !defined(DUK_DEBUG_PORT) -+#define DUK_DEBUG_PORT 9091 -+#endif -+ -+#if 0 -+#define DEBUG_PRINTS -+#endif -+ -+static int server_sock = -1; -+static int client_sock = -1; -+ -+/* -+ * Transport init and finish -+ */ -+ -+void duk_trans_socket_init(void) { -+ struct sockaddr_in addr; -+ int on; -+ -+ server_sock = socket(AF_INET, SOCK_STREAM, 0); -+ if (server_sock < 0) { -+ fprintf(stderr, "%s: failed to create server socket: %s\n", -+ __FILE__, strerror(errno)); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ on = 1; -+ if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) < 0) { -+ fprintf(stderr, "%s: failed to set SO_REUSEADDR for server socket: %s\n", -+ __FILE__, strerror(errno)); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ memset((void *) &addr, 0, sizeof(addr)); -+ addr.sin_family = AF_INET; -+ addr.sin_addr.s_addr = INADDR_ANY; -+ addr.sin_port = htons(DUK_DEBUG_PORT); -+ -+ if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ fprintf(stderr, "%s: failed to bind server socket: %s\n", -+ __FILE__, strerror(errno)); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ listen(server_sock, 1 /*backlog*/); -+ return; -+ -+ fail: -+ if (server_sock >= 0) { -+ (void) close(server_sock); -+ server_sock = -1; -+ } -+} -+ -+void duk_trans_socket_finish(void) { -+ if (client_sock >= 0) { -+ (void) close(client_sock); -+ client_sock = -1; -+ } -+ if (server_sock >= 0) { -+ (void) close(server_sock); -+ server_sock = -1; -+ } -+} -+ -+void duk_trans_socket_waitconn(void) { -+ struct sockaddr_in addr; -+ socklen_t sz; -+ -+ if (server_sock < 0) { -+ fprintf(stderr, "%s: no server socket, skip waiting for connection\n", -+ __FILE__); -+ fflush(stderr); -+ return; -+ } -+ if (client_sock >= 0) { -+ (void) close(client_sock); -+ client_sock = -1; -+ } -+ -+ fprintf(stderr, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT); -+ fflush(stderr); -+ -+ sz = (socklen_t) sizeof(addr); -+ client_sock = accept(server_sock, (struct sockaddr *) &addr, &sz); -+ if (client_sock < 0) { -+ fprintf(stderr, "%s: accept() failed, skip waiting for connection: %s\n", -+ __FILE__, strerror(errno)); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ fprintf(stderr, "Debug connection established\n"); -+ fflush(stderr); -+ -+ /* XXX: For now, close the listen socket because we won't accept new -+ * connections anyway. A better implementation would allow multiple -+ * debug attaches. -+ */ -+ -+ if (server_sock >= 0) { -+ (void) close(server_sock); -+ server_sock = -1; -+ } -+ return; -+ -+ fail: -+ if (client_sock >= 0) { -+ (void) close(client_sock); -+ client_sock = -1; -+ } -+} -+ -+/* -+ * Duktape callbacks -+ */ -+ -+/* Duktape debug transport callback: (possibly partial) read. */ -+duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length) { -+ ssize_t ret; -+ -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", -+ __func__, (void *) udata, (void *) buffer, (long) length); -+ fflush(stderr); -+#endif -+ -+ if (client_sock < 0) { -+ return 0; -+ } -+ -+ if (length == 0) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: read request length == 0, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ if (buffer == NULL) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: read request buffer == NULL, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ /* In a production quality implementation there would be a sanity -+ * timeout here to recover from "black hole" disconnects. -+ */ -+ -+ ret = read(client_sock, (void *) buffer, (size_t) length); -+ if (ret < 0) { -+ fprintf(stderr, "%s: debug read failed, closing connection: %s\n", -+ __FILE__, strerror(errno)); -+ fflush(stderr); -+ goto fail; -+ } else if (ret == 0) { -+ fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } else if (ret > (ssize_t) length) { -+ fprintf(stderr, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n", -+ __FILE__, (long) ret, (long) length); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ return (duk_size_t) ret; -+ -+ fail: -+ if (client_sock >= 0) { -+ (void) close(client_sock); -+ client_sock = -1; -+ } -+ return 0; -+} -+ -+/* Duktape debug transport callback: (possibly partial) write. */ -+duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length) { -+ ssize_t ret; -+ -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", -+ __func__, (void *) udata, (const void *) buffer, (long) length); -+ fflush(stderr); -+#endif -+ -+ if (client_sock < 0) { -+ return 0; -+ } -+ -+ if (length == 0) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: write request length == 0, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ if (buffer == NULL) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: write request buffer == NULL, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ /* In a production quality implementation there would be a sanity -+ * timeout here to recover from "black hole" disconnects. -+ */ -+ -+ ret = write(client_sock, (const void *) buffer, (size_t) length); -+ if (ret <= 0 || ret > (ssize_t) length) { -+ fprintf(stderr, "%s: debug write failed, closing connection: %s\n", -+ __FILE__, strerror(errno)); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ return (duk_size_t) ret; -+ -+ fail: -+ if (client_sock >= 0) { -+ (void) close(client_sock); -+ client_sock = -1; -+ } -+ return 0; -+} -+ -+duk_size_t duk_trans_socket_peek_cb(void *udata) { -+#if defined(USE_SELECT) -+ struct timeval tm; -+ fd_set rfds; -+ int select_rc; -+#else -+ struct pollfd fds[1]; -+ int poll_rc; -+#endif -+ -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata); -+ fflush(stderr); -+#endif -+ -+ if (client_sock < 0) { -+ return 0; -+ } -+#if defined(USE_SELECT) -+ FD_ZERO(&rfds); -+ FD_SET(client_sock, &rfds); -+ tm.tv_sec = tm.tv_usec = 0; -+ select_rc = select(client_sock + 1, &rfds, NULL, NULL, &tm); -+ if (select_rc == 0) { -+ return 0; -+ } else if (select_rc == 1) { -+ return 1; -+ } -+ goto fail; -+#else /* USE_SELECT */ -+ fds[0].fd = client_sock; -+ fds[0].events = POLLIN; -+ fds[0].revents = 0; -+ -+ poll_rc = poll(fds, 1, 0); -+ if (poll_rc < 0) { -+ fprintf(stderr, "%s: poll returned < 0, closing connection: %s\n", -+ __FILE__, strerror(errno)); -+ fflush(stderr); -+ goto fail; /* also returns 0, which is correct */ -+ } else if (poll_rc > 1) { -+ fprintf(stderr, "%s: poll returned > 1, treating like 1\n", -+ __FILE__); -+ fflush(stderr); -+ return 1; /* should never happen */ -+ } else if (poll_rc == 0) { -+ return 0; /* nothing to read */ -+ } else { -+ return 1; /* something to read */ -+ } -+#endif /* USE_SELECT */ -+ fail: -+ if (client_sock >= 0) { -+ (void) close(client_sock); -+ client_sock = -1; -+ } -+ return 0; -+} -+ -+void duk_trans_socket_read_flush_cb(void *udata) { -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata); -+ fflush(stderr); -+#endif -+ -+ /* Read flush: Duktape may not be making any more read calls at this -+ * time. If the transport maintains a receive window, it can use a -+ * read flush as a signal to update the window status to the remote -+ * peer. A read flush is guaranteed to occur before Duktape stops -+ * reading for a while; it may occur in other situations as well so -+ * it's not a 100% reliable indication. -+ */ -+ -+ /* This TCP transport requires no read flush handling so ignore. -+ * You can also pass a NULL to duk_debugger_attach() and not -+ * implement this callback at all. -+ */ -+} -+ -+void duk_trans_socket_write_flush_cb(void *udata) { -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata); -+ fflush(stderr); -+#endif -+ -+ /* Write flush. If the transport combines multiple writes -+ * before actually sending, a write flush is an indication -+ * to write out any pending bytes: Duktape may not be doing -+ * any more writes on this occasion. -+ */ -+ -+ /* This TCP transport requires no write flush handling so ignore. -+ * You can also pass a NULL to duk_debugger_attach() and not -+ * implement this callback at all. -+ */ -+ return; -+} -diff --git a/dist/source/examples/debug-trans-socket/duk_trans_socket_windows.c b/dist/source/examples/debug-trans-socket/duk_trans_socket_windows.c -new file mode 100644 -index 0000000..59bee04 ---- /dev/null -+++ b/dist/source/examples/debug-trans-socket/duk_trans_socket_windows.c -@@ -0,0 +1,419 @@ -+/* -+ * Example debug transport using a Windows TCP socket -+ * -+ * Provides a TCP server socket which a debug client can connect to. -+ * After that data is just passed through. -+ * -+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx -+ * -+ * Compiling 'duk' with debugger support using MSVC (Visual Studio): -+ * -+ * > python2 tools\configure.py \ -+ * --output-directory prep -+ * -DDUK_USE_DEBUGGER_SUPPORT -DDUK_USE_INTERRUPT_COUNTER -+ * > cl /W3 /O2 /Feduk.exe \ -+ * /DDUK_CMDLINE_DEBUGGER_SUPPORT -+ * /Iexamples\debug-trans-socket /Iprep -+ * examples\cmdline\duk_cmdline.c -+ * examples\debug-trans-socket\duk_trans_socket_windows.c -+ * prep\duktape.c -+ * -+ * With MinGW: -+ * -+ * $ python2 tools\configure.py \ -+ * --output-directory prep -+ * -DDUK_USE_DEBUGGER_SUPPORT -DDUK_USE_INTERRUPT_COUNTER -+ * $ gcc -oduk.exe -Wall -O2 \ -+ * -DDUK_CMDLINE_DEBUGGER_SUPPORT \ -+ * -Iexamples/debug-trans-socket -Iprep \ -+ * examples/cmdline/duk_cmdline.c \ -+ * examples/debug-trans-socket/duk_trans_socket_windows.c \ -+ * prep/duktape.c -lm -lws2_32 -+ */ -+ -+#undef UNICODE -+#if !defined(WIN32_LEAN_AND_MEAN) -+#define WIN32_LEAN_AND_MEAN -+#endif -+ -+/* MinGW workaround for missing getaddrinfo() etc: -+ * http://programmingrants.blogspot.fi/2009/09/tips-on-undefined-reference-to.html -+ */ -+#if defined(__MINGW32__) || defined(__MINGW64__) -+#if !defined(_WIN32_WINNT) -+#define _WIN32_WINNT 0x0501 -+#endif -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include "duktape.h" -+#include "duk_trans_socket.h" -+ -+#if defined(_MSC_VER) -+#pragma comment (lib, "Ws2_32.lib") -+#endif -+ -+#if !defined(DUK_DEBUG_PORT) -+#define DUK_DEBUG_PORT 9091 -+#endif -+#if !defined(DUK_DEBUG_ADDRESS) -+#define DUK_DEBUG_ADDRESS "0.0.0.0" -+#endif -+#define DUK__STRINGIFY_HELPER(x) #x -+#define DUK__STRINGIFY(x) DUK__STRINGIFY_HELPER(x) -+ -+#if 0 -+#define DEBUG_PRINTS -+#endif -+ -+static SOCKET server_sock = INVALID_SOCKET; -+static SOCKET client_sock = INVALID_SOCKET; -+static int wsa_inited = 0; -+ -+/* -+ * Transport init and finish -+ */ -+ -+void duk_trans_socket_init(void) { -+ WSADATA wsa_data; -+ struct addrinfo hints; -+ struct addrinfo *result = NULL; -+ int rc; -+ -+ memset((void *) &wsa_data, 0, sizeof(wsa_data)); -+ memset((void *) &hints, 0, sizeof(hints)); -+ -+ rc = WSAStartup(MAKEWORD(2, 2), &wsa_data); -+ if (rc != 0) { -+ fprintf(stderr, "%s: WSAStartup() failed: %d\n", __FILE__, rc); -+ fflush(stderr); -+ goto fail; -+ } -+ wsa_inited = 1; -+ -+ hints.ai_family = AF_UNSPEC; -+ hints.ai_socktype = SOCK_STREAM; -+ hints.ai_protocol = IPPROTO_TCP; -+ hints.ai_flags = AI_PASSIVE; -+ -+ rc = getaddrinfo(DUK_DEBUG_ADDRESS, DUK__STRINGIFY(DUK_DEBUG_PORT), &hints, &result); -+ if (rc != 0) { -+ fprintf(stderr, "%s: getaddrinfo() failed: %d\n", __FILE__, rc); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ server_sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol); -+ if (server_sock == INVALID_SOCKET) { -+ fprintf(stderr, "%s: socket() failed with error: %ld\n", -+ __FILE__, (long) WSAGetLastError()); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ rc = bind(server_sock, result->ai_addr, (int) result->ai_addrlen); -+ if (rc == SOCKET_ERROR) { -+ fprintf(stderr, "%s: bind() failed with error: %ld\n", -+ __FILE__, (long) WSAGetLastError()); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ rc = listen(server_sock, SOMAXCONN); -+ if (rc == SOCKET_ERROR) { -+ fprintf(stderr, "%s: listen() failed with error: %ld\n", -+ __FILE__, (long) WSAGetLastError()); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ if (result != NULL) { -+ freeaddrinfo(result); -+ result = NULL; -+ } -+ return; -+ -+ fail: -+ if (result != NULL) { -+ freeaddrinfo(result); -+ result = NULL; -+ } -+ if (server_sock != INVALID_SOCKET) { -+ (void) closesocket(server_sock); -+ server_sock = INVALID_SOCKET; -+ } -+ if (wsa_inited) { -+ WSACleanup(); -+ wsa_inited = 0; -+ } -+} -+ -+void duk_trans_socket_finish(void) { -+ if (client_sock != INVALID_SOCKET) { -+ (void) closesocket(client_sock); -+ client_sock = INVALID_SOCKET; -+ } -+ if (server_sock != INVALID_SOCKET) { -+ (void) closesocket(server_sock); -+ server_sock = INVALID_SOCKET; -+ } -+ if (wsa_inited) { -+ WSACleanup(); -+ wsa_inited = 0; -+ } -+} -+ -+void duk_trans_socket_waitconn(void) { -+ if (server_sock == INVALID_SOCKET) { -+ fprintf(stderr, "%s: no server socket, skip waiting for connection\n", -+ __FILE__); -+ fflush(stderr); -+ return; -+ } -+ if (client_sock != INVALID_SOCKET) { -+ (void) closesocket(client_sock); -+ client_sock = INVALID_SOCKET; -+ } -+ -+ fprintf(stderr, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT); -+ fflush(stderr); -+ -+ client_sock = accept(server_sock, NULL, NULL); -+ if (client_sock == INVALID_SOCKET) { -+ fprintf(stderr, "%s: accept() failed with error %ld, skip waiting for connection\n", -+ __FILE__, (long) WSAGetLastError()); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ fprintf(stderr, "Debug connection established\n"); -+ fflush(stderr); -+ -+ /* XXX: For now, close the listen socket because we won't accept new -+ * connections anyway. A better implementation would allow multiple -+ * debug attaches. -+ */ -+ -+ if (server_sock != INVALID_SOCKET) { -+ (void) closesocket(server_sock); -+ server_sock = INVALID_SOCKET; -+ } -+ return; -+ -+ fail: -+ if (client_sock != INVALID_SOCKET) { -+ (void) closesocket(client_sock); -+ client_sock = INVALID_SOCKET; -+ } -+} -+ -+/* -+ * Duktape callbacks -+ */ -+ -+/* Duktape debug transport callback: (possibly partial) read. */ -+duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length) { -+ int ret; -+ -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", -+ __FUNCTION__, (void *) udata, (void *) buffer, (long) length); -+ fflush(stderr); -+#endif -+ -+ if (client_sock == INVALID_SOCKET) { -+ return 0; -+ } -+ -+ if (length == 0) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: read request length == 0, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ if (buffer == NULL) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: read request buffer == NULL, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ /* In a production quality implementation there would be a sanity -+ * timeout here to recover from "black hole" disconnects. -+ */ -+ -+ ret = recv(client_sock, buffer, (int) length, 0); -+ if (ret < 0) { -+ fprintf(stderr, "%s: debug read failed, error %d, closing connection\n", -+ __FILE__, ret); -+ fflush(stderr); -+ goto fail; -+ } else if (ret == 0) { -+ fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } else if (ret > (int) length) { -+ fprintf(stderr, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n", -+ __FILE__, (long) ret, (long) length); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ return (duk_size_t) ret; -+ -+ fail: -+ if (client_sock != INVALID_SOCKET) { -+ (void) closesocket(client_sock); -+ client_sock = INVALID_SOCKET; -+ } -+ return 0; -+} -+ -+/* Duktape debug transport callback: (possibly partial) write. */ -+duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length) { -+ int ret; -+ -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", -+ __FUNCTION__, (void *) udata, (const void *) buffer, (long) length); -+ fflush(stderr); -+#endif -+ -+ if (client_sock == INVALID_SOCKET) { -+ return 0; -+ } -+ -+ if (length == 0) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: write request length == 0, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ if (buffer == NULL) { -+ /* This shouldn't happen. */ -+ fprintf(stderr, "%s: write request buffer == NULL, closing connection\n", -+ __FILE__); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ /* In a production quality implementation there would be a sanity -+ * timeout here to recover from "black hole" disconnects. -+ */ -+ -+ ret = send(client_sock, buffer, (int) length, 0); -+ if (ret <= 0 || ret > (int) length) { -+ fprintf(stderr, "%s: debug write failed, ret %d, closing connection\n", -+ __FILE__, ret); -+ fflush(stderr); -+ goto fail; -+ } -+ -+ return (duk_size_t) ret; -+ -+ fail: -+ if (client_sock != INVALID_SOCKET) { -+ (void) closesocket(INVALID_SOCKET); -+ client_sock = INVALID_SOCKET; -+ } -+ return 0; -+} -+ -+duk_size_t duk_trans_socket_peek_cb(void *udata) { -+ u_long avail; -+ int rc; -+ -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); -+ fflush(stderr); -+#endif -+ -+ if (client_sock == INVALID_SOCKET) { -+ return 0; -+ } -+ -+ avail = 0; -+ rc = ioctlsocket(client_sock, FIONREAD, &avail); -+ if (rc != 0) { -+ fprintf(stderr, "%s: ioctlsocket() returned %d, closing connection\n", -+ __FILE__, rc); -+ fflush(stderr); -+ goto fail; /* also returns 0, which is correct */ -+ } else { -+ if (avail == 0) { -+ return 0; /* nothing to read */ -+ } else { -+ return 1; /* something to read */ -+ } -+ } -+ /* never here */ -+ -+ fail: -+ if (client_sock != INVALID_SOCKET) { -+ (void) closesocket(client_sock); -+ client_sock = INVALID_SOCKET; -+ } -+ return 0; -+} -+ -+void duk_trans_socket_read_flush_cb(void *udata) { -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); -+ fflush(stderr); -+#endif -+ -+ /* Read flush: Duktape may not be making any more read calls at this -+ * time. If the transport maintains a receive window, it can use a -+ * read flush as a signal to update the window status to the remote -+ * peer. A read flush is guaranteed to occur before Duktape stops -+ * reading for a while; it may occur in other situations as well so -+ * it's not a 100% reliable indication. -+ */ -+ -+ /* This TCP transport requires no read flush handling so ignore. -+ * You can also pass a NULL to duk_debugger_attach() and not -+ * implement this callback at all. -+ */ -+} -+ -+void duk_trans_socket_write_flush_cb(void *udata) { -+ (void) udata; /* not needed by the example */ -+ -+#if defined(DEBUG_PRINTS) -+ fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); -+ fflush(stderr); -+#endif -+ -+ /* Write flush. If the transport combines multiple writes -+ * before actually sending, a write flush is an indication -+ * to write out any pending bytes: Duktape may not be doing -+ * any more writes on this occasion. -+ */ -+ -+ /* This TCP transport requires no write flush handling so ignore. -+ * You can also pass a NULL to duk_debugger_attach() and not -+ * implement this callback at all. -+ */ -+ return; -+} -+ -+#undef DUK__STRINGIFY_HELPER -+#undef DUK__STRINGIFY -diff --git a/dist/source/examples/dummy-date-provider/README.rst b/dist/source/examples/dummy-date-provider/README.rst -new file mode 100644 -index 0000000..bc62779 ---- /dev/null -+++ b/dist/source/examples/dummy-date-provider/README.rst -@@ -0,0 +1,5 @@ -+==================================== -+Dummy external Date provider example -+==================================== -+ -+This example implements a dummy, minimal external Date provider. -diff --git a/dist/source/examples/dummy-date-provider/dummy_date_provider.c b/dist/source/examples/dummy-date-provider/dummy_date_provider.c -new file mode 100644 -index 0000000..9c9e716 ---- /dev/null -+++ b/dist/source/examples/dummy-date-provider/dummy_date_provider.c -@@ -0,0 +1,27 @@ -+/* -+ * Dummy Date provider -+ * -+ * There are two minimally required macros which you must provide in -+ * duk_config.h: -+ * -+ * extern duk_double_t dummy_get_now(void); -+ * -+ * #define DUK_USE_DATE_GET_NOW(ctx) dummy_get_now() -+ * #define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) 0 -+ * -+ * Note that since the providers are macros, you don't need to use -+ * all arguments. Similarly, you can "return" fixed values as -+ * constants. Above, local timezone offset is always zero i.e. -+ * we're always in UTC. -+ * -+ * You can also provide optional macros to parse and format timestamps -+ * in a platform specific format. If not provided, Duktape will use -+ * ISO 8601 only (which is often good enough). -+ */ -+ -+#include "duktape.h" -+ -+duk_double_t dummy_get_now(void) { -+ /* Return a fixed time here as a dummy example. */ -+ return -11504520000.0; -+} -diff --git a/dist/source/examples/eval/README.rst b/dist/source/examples/eval/README.rst -new file mode 100644 -index 0000000..eed1806 ---- /dev/null -+++ b/dist/source/examples/eval/README.rst -@@ -0,0 +1,5 @@ -+============ -+Eval example -+============ -+ -+Evaluate expressions from command line. -diff --git a/dist/source/examples/eval/eval.c b/dist/source/examples/eval/eval.c -new file mode 100644 -index 0000000..731f451 ---- /dev/null -+++ b/dist/source/examples/eval/eval.c -@@ -0,0 +1,55 @@ -+/* -+ * Very simple example program for evaluating expressions from -+ * command line -+ */ -+ -+#include "duktape.h" -+#include -+ -+static duk_ret_t native_print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_to_string(ctx, -1)); -+ return 0; -+} -+ -+static void usage_exit(void) { -+ fprintf(stderr, "Usage: eval [] ...\n"); -+ fflush(stderr); -+ exit(1); -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ int i; -+ const char *res; -+ duk_int_t rc; -+ -+ if (argc < 2) { -+ usage_exit(); -+ } -+ -+ ctx = duk_create_heap_default(); -+ -+ duk_push_c_function(ctx, native_print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ -+ for (i = 1; i < argc; i++) { -+ printf("=== eval: '%s' ===\n", argv[i]); -+ duk_push_string(ctx, argv[i]); -+ rc = duk_peval(ctx); -+ if (rc != 0) { -+ duk_safe_to_stacktrace(ctx, -1); -+ } else { -+ duk_safe_to_string(ctx, -1); -+ } -+ res = duk_get_string(ctx, -1); -+ printf("%s\n", res ? res : "null"); -+ duk_pop(ctx); -+ } -+ -+ duk_destroy_heap(ctx); -+ -+ return 0; -+} -diff --git a/dist/source/examples/eventloop/README.rst b/dist/source/examples/eventloop/README.rst -new file mode 100644 -index 0000000..c67e4f5 ---- /dev/null -+++ b/dist/source/examples/eventloop/README.rst -@@ -0,0 +1,72 @@ -+================== -+Eventloop examples -+================== -+ -+Overview and usage -+================== -+ -+A few examples on how an event loop can be implemented with Duktape, mainly -+illlustrating how the Duktape interface works (not how event loops should be -+built otherwise). -+ -+To test (Linux only, perhaps other Unix):: -+ -+ $ ./evloop timer-test.js # run with ECMAScript eventloop -+ $ ./evloop -c timer-test.js # run with C eventloop -+ -+Implementation approaches -+========================= -+ -+There are several approaches to implementation timers. Here we demonstrate -+two main approaches: -+ -+1. Using a C eventloop which calls into ECMAScript. All the event loop state -+ like timers, sockets, etc, is held in C structures. -+ (See ``c_eventloop.c`` and ``c_eventloop.js``.) -+ -+2. Using an ECMAScript eventloop which never returns. All the event loop state -+ can be managed with ECMAScript code instead of C structures. The ECMAScript -+ eventloop calls a Duktape/C helper to do the lowest level poll() call. -+ (See ``ecma_eventloop.js``.) -+ -+Services provided -+================= -+ -+The event loop API provided by both examples is the same, and includes: -+ -+* Timers: setTimeout, clearTimeout, setInterval, clearInterval -+ -+* Sockets: simple network sockets -+ -+In addition there are a few synchronous API bindings which are not event loop -+related: -+ -+* File I/O -+ -+Limitations -+=========== -+ -+This is **not** a production quality event loop. This is on purpose, to -+keep the example somewhat simple. Some shortcomings include: -+ -+* A production quality event loop would track its internal state (active -+ timers and sockets) much more efficiently. In general memory usage and -+ code footprint can be reduced. -+ -+* Buffer churn caused by allocating a new buffer for every socket read -+ should be eliminated by reusing buffers where appropriate. Although -+ churn doesn't increase memory footprint with reference counting, it -+ is slower than reusing buffers and might increase memory fragmentation. -+ -+* There is no way to suspend reading or writing in the example. Adding -+ them is straightforward: the poll set needs to be managed dynamically. -+ -+* The example uses poll() while one should use epoll() on Linux, kqueue() -+ on BSD systems, etc. -+ -+* Timers are not very accurate, e.g. setInterval() does not try to guarantee -+ a steady schedule. Instead, the next interval is scheduled after the -+ current callback has finished. This is not the best behavior for some -+ environments, but avoids bunching callbacks. -+ -+* Error handling is mostly missing. -diff --git a/dist/source/examples/eventloop/basic-test.js b/dist/source/examples/eventloop/basic-test.js -new file mode 100644 -index 0000000..77605c0 ---- /dev/null -+++ b/dist/source/examples/eventloop/basic-test.js -@@ -0,0 +1,16 @@ -+/* -+ * A few basic tests -+ */ -+ -+var count = 0; -+var intervalId; -+ -+setTimeout(function (x) { print('timer 1', x); }, 1234, 'foo'); -+setTimeout('print("timer 2");', 4321); -+setTimeout(function () { print('timer 3'); }, 2345); -+intervalId = setInterval(function (x, y) { -+ print('interval', ++count, x, y); -+ if (count >= 10) { -+ clearInterval(intervalId); -+ } -+}, 400, 'foo', 'bar'); -diff --git a/dist/source/examples/eventloop/c_eventloop.c b/dist/source/examples/eventloop/c_eventloop.c -new file mode 100644 -index 0000000..24cebbb ---- /dev/null -+++ b/dist/source/examples/eventloop/c_eventloop.c -@@ -0,0 +1,626 @@ -+/* -+ * C eventloop example. -+ * -+ * Timer management is similar to eventloop.js but implemented in C. -+ * In particular, timer insertion is an O(n) operation; in a real world -+ * eventloop based on a heap insertion would be O(log N). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "duktape.h" -+#include "c_eventloop.h" -+ -+#if !defined(DUKTAPE_EVENTLOOP_DEBUG) -+#define DUKTAPE_EVENTLOOP_DEBUG 0 /* set to 1 to debug with printf */ -+#endif -+ -+#define TIMERS_SLOT_NAME "eventTimers" -+#define MIN_DELAY 1.0 -+#define MIN_WAIT 1.0 -+#define MAX_WAIT 60000.0 -+#define MAX_EXPIRIES 10 -+ -+#define MAX_FDS 256 -+#define MAX_TIMERS 4096 /* this is quite excessive for embedded use, but good for testing */ -+ -+typedef struct { -+ int64_t id; /* numeric ID (returned from e.g. setTimeout); zero if unused */ -+ double target; /* next target time */ -+ double delay; /* delay/interval */ -+ int oneshot; /* oneshot=1 (setTimeout), repeated=0 (setInterval) */ -+ int removed; /* timer has been requested for removal */ -+ -+ /* The callback associated with the timer is held in the "global stash", -+ * in .eventTimers[String(id)]. The references must be deleted -+ * when a timer struct is deleted. -+ */ -+} ev_timer; -+ -+/* Active timers. Dense list, terminates to end of list or first unused timer. -+ * The list is sorted by 'target', with lowest 'target' (earliest expiry) last -+ * in the list. When a timer's callback is being called, the timer is moved -+ * to 'timer_expiring' as it needs special handling should the user callback -+ * delete that particular timer. -+ */ -+static ev_timer timer_list[MAX_TIMERS]; -+static ev_timer timer_expiring; -+static int timer_count; /* last timer at timer_count - 1 */ -+static int64_t timer_next_id = 1; -+ -+/* Socket poll state. */ -+static struct pollfd poll_list[MAX_FDS]; -+static int poll_count = 0; -+ -+/* Misc */ -+static int exit_requested = 0; -+ -+/* Get Javascript compatible 'now' timestamp (millisecs since 1970). */ -+static double get_now(void) { -+ struct timeval tv; -+ int rc; -+ -+ rc = gettimeofday(&tv, NULL); -+ if (rc != 0) { -+ /* Should never happen, so return whatever. */ -+ return 0.0; -+ } -+ return ((double) tv.tv_sec) * 1000.0 + ((double) tv.tv_usec) / 1000.0; -+} -+ -+static ev_timer *find_nearest_timer(void) { -+ /* Last timer expires first (list is always kept sorted). */ -+ if (timer_count <= 0) { -+ return NULL; -+ } -+ return timer_list + timer_count - 1; -+} -+ -+/* Bubble last timer on timer list backwards until it has been moved to -+ * its proper sorted position (based on 'target' time). -+ */ -+static void bubble_last_timer(void) { -+ int i; -+ int n = timer_count; -+ ev_timer *t; -+ ev_timer tmp; -+ -+ for (i = n - 1; i > 0; i--) { -+ /* Timer to bubble is at index i, timer to compare to is -+ * at i-1 (both guaranteed to exist). -+ */ -+ t = timer_list + i; -+ if (t->target <= (t-1)->target) { -+ /* 't' expires earlier than (or same time as) 't-1', so we're done. */ -+ break; -+ } else { -+ /* 't' expires later than 't-1', so swap them and repeat. */ -+ memcpy((void *) &tmp, (void *) (t - 1), sizeof(ev_timer)); -+ memcpy((void *) (t - 1), (void *) t, sizeof(ev_timer)); -+ memcpy((void *) t, (void *) &tmp, sizeof(ev_timer)); -+ } -+ } -+} -+ -+static void expire_timers(duk_context *ctx) { -+ ev_timer *t; -+ int sanity = MAX_EXPIRIES; -+ double now; -+ int rc; -+ -+ /* Because a user callback can mutate the timer list (by adding or deleting -+ * a timer), we expire one timer and then rescan from the end again. There -+ * is a sanity limit on how many times we do this per expiry round. -+ */ -+ -+ duk_push_global_stash(ctx); -+ duk_get_prop_string(ctx, -1, TIMERS_SLOT_NAME); -+ -+ /* [ ... stash eventTimers ] */ -+ -+ now = get_now(); -+ while (sanity-- > 0) { -+ /* -+ * If exit has been requested, exit without running further -+ * callbacks. -+ */ -+ -+ if (exit_requested) { -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "exit requested, exiting timer expiry loop\n"); -+ fflush(stderr); -+#endif -+ break; -+ } -+ -+ /* -+ * Expired timer(s) still exist? -+ */ -+ -+ if (timer_count <= 0) { -+ break; -+ } -+ t = timer_list + timer_count - 1; -+ if (t->target > now) { -+ break; -+ } -+ -+ /* -+ * Move the timer to 'expiring' for the duration of the callback. -+ * Mark a one-shot timer deleted, compute a new target for an interval. -+ */ -+ -+ memcpy((void *) &timer_expiring, (void *) t, sizeof(ev_timer)); -+ memset((void *) t, 0, sizeof(ev_timer)); -+ timer_count--; -+ t = &timer_expiring; -+ -+ if (t->oneshot) { -+ t->removed = 1; -+ } else { -+ t->target = now + t->delay; /* XXX: or t->target + t->delay? */ -+ } -+ -+ /* -+ * Call timer callback. The callback can operate on the timer list: -+ * add new timers, remove timers. The callback can even remove the -+ * expired timer whose callback we're calling. However, because the -+ * timer being expired has been moved to 'timer_expiring', we don't -+ * need to worry about the timer's offset changing on the timer list. -+ */ -+ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "calling user callback for timer id %d\n", (int) t->id); -+ fflush(stderr); -+#endif -+ -+ duk_push_number(ctx, (double) t->id); -+ duk_get_prop(ctx, -2); /* -> [ ... stash eventTimers func ] */ -+ rc = duk_pcall(ctx, 0 /*nargs*/); /* -> [ ... stash eventTimers retval ] */ -+ if (rc != 0) { -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "timer callback failed for timer %d: %s\n", (int) t->id, duk_to_string(ctx, -1)); -+ fflush(stderr); -+#endif -+ } -+ duk_pop(ctx); /* ignore errors for now -> [ ... stash eventTimers ] */ -+ -+ if (t->removed) { -+ /* One-shot timer (always removed) or removed by user callback. */ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "deleting callback state for timer %d\n", (int) t->id); -+ fflush(stderr); -+#endif -+ duk_push_number(ctx, (double) t->id); -+ duk_del_prop(ctx, -2); -+ } else { -+ /* Interval timer, not removed by user callback. Queue back to -+ * timer list and bubble to its final sorted position. -+ */ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "queueing timer %d back into active list\n", (int) t->id); -+ fflush(stderr); -+#endif -+ if (timer_count >= MAX_TIMERS) { -+ (void) duk_error(ctx, DUK_ERR_RANGE_ERROR, "out of timer slots"); -+ } -+ memcpy((void *) (timer_list + timer_count), (void *) t, sizeof(ev_timer)); -+ timer_count++; -+ bubble_last_timer(); -+ } -+ } -+ -+ memset((void *) &timer_expiring, 0, sizeof(ev_timer)); -+ -+ duk_pop_2(ctx); /* -> [ ... ] */ -+} -+ -+static void compact_poll_list(void) { -+ int i, j, n; -+ -+ /* i = input index -+ * j = output index (initially same as i) -+ */ -+ -+ n = poll_count; -+ for (i = 0, j = 0; i < n; i++) { -+ struct pollfd *pfd = poll_list + i; -+ if (pfd->fd == 0) { -+ /* keep output index the same */ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "remove pollfd (index %d): fd=%d, events=%d, revents=%d\n", -+ i, pfd->fd, pfd->events, pfd->revents), -+ fflush(stderr); -+#endif -+ -+ continue; -+ } -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "keep pollfd (index %d -> %d): fd=%d, events=%d, revents=%d\n", -+ i, j, pfd->fd, pfd->events, pfd->revents), -+ fflush(stderr); -+#endif -+ if (i != j) { -+ /* copy only if indices have diverged */ -+ memcpy((void *) (poll_list + j), (void *) (poll_list + i), sizeof(struct pollfd)); -+ } -+ j++; -+ } -+ -+ if (j < poll_count) { -+ /* zeroize unused entries for sanity */ -+ memset((void *) (poll_list + j), 0, (poll_count - j) * sizeof(struct pollfd)); -+ } -+ -+ poll_count = j; -+} -+ -+duk_ret_t eventloop_run(duk_context *ctx, void *udata) { -+ ev_timer *t; -+ double now; -+ double diff; -+ int timeout; -+ int rc; -+ int i, n; -+ int idx_eventloop; -+ int idx_fd_handler; -+ -+ (void) udata; -+ -+ /* The ECMAScript poll handler is passed through EventLoop.fdPollHandler -+ * which c_eventloop.js sets before we come here. -+ */ -+ duk_push_global_object(ctx); -+ duk_get_prop_string(ctx, -1, "EventLoop"); -+ duk_get_prop_string(ctx, -1, "fdPollHandler"); /* -> [ global EventLoop fdPollHandler ] */ -+ idx_fd_handler = duk_get_top_index(ctx); -+ idx_eventloop = idx_fd_handler - 1; -+ -+ for (;;) { -+ /* -+ * Expire timers. -+ */ -+ -+ expire_timers(ctx); -+ -+ /* -+ * If exit requested, bail out as fast as possible. -+ */ -+ -+ if (exit_requested) { -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "exit requested, exiting event loop\n"); -+ fflush(stderr); -+#endif -+ break; -+ } -+ -+ /* -+ * Compact poll list by removing pollfds with fd == 0. -+ */ -+ -+ compact_poll_list(); -+ -+ /* -+ * Determine poll() timeout (as close to poll() as possible as -+ * the wait is relative). -+ */ -+ -+ now = get_now(); -+ t = find_nearest_timer(); -+ if (t) { -+ diff = t->target - now; -+ if (diff < MIN_WAIT) { -+ diff = MIN_WAIT; -+ } else if (diff > MAX_WAIT) { -+ diff = MAX_WAIT; -+ } -+ timeout = (int) diff; /* clamping ensures that fits */ -+ } else { -+ if (poll_count == 0) { -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "no timers and no sockets to poll, exiting\n"); -+ fflush(stderr); -+#endif -+ break; -+ } -+ timeout = (int) MAX_WAIT; -+ } -+ -+ /* -+ * Poll for activity or timeout. -+ */ -+ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "going to poll, timeout %d ms, pollfd count %d\n", timeout, poll_count); -+ fflush(stderr); -+#endif -+ -+ rc = poll(poll_list, poll_count, timeout); -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "poll rc: %d\n", rc); -+ fflush(stderr); -+#endif -+ if (rc < 0) { -+ /* error */ -+ } else if (rc == 0) { -+ /* timeout */ -+ } else { -+ /* 'rc' fds active */ -+ } -+ -+ /* -+ * Check socket activity, handle all sockets. Handling is offloaded to -+ * ECMAScript code (fd + revents). -+ * -+ * If FDs are removed from the poll list while we're processing callbacks, -+ * the entries are simply marked unused (fd set to 0) without actually -+ * removing them from the poll list. This ensures indices are not -+ * disturbed. The poll list is compacted before next poll(). -+ */ -+ -+ n = (rc == 0 ? 0 : poll_count); /* if timeout, no need to check pollfd */ -+ for (i = 0; i < n; i++) { -+ struct pollfd *pfd = poll_list + i; -+ -+ if (pfd->fd == 0) { -+ /* deleted, perhaps by previous callback */ -+ continue; -+ } -+ -+ if (pfd->revents) { -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "fd %d has revents: %d\n", (int) pfd->fd, (int) pfd->revents); -+ fflush(stderr); -+#endif -+ duk_dup(ctx, idx_fd_handler); -+ duk_dup(ctx, idx_eventloop); -+ duk_push_int(ctx, pfd->fd); -+ duk_push_int(ctx, pfd->revents); -+ rc = duk_pcall_method(ctx, 2 /*nargs*/); -+ if (rc) { -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "fd callback failed for fd %d: %s\n", (int) pfd->fd, duk_to_string(ctx, -1)); -+ fflush(stderr); -+#endif -+ } -+ duk_pop(ctx); -+ -+ pfd->revents = 0; -+ } -+ -+ } -+ } -+ -+ duk_pop_n(ctx, 3); -+ -+ return 0; -+} -+ -+static int create_timer(duk_context *ctx) { -+ double delay; -+ int oneshot; -+ int idx; -+ int64_t timer_id; -+ double now; -+ ev_timer *t; -+ -+ now = get_now(); -+ -+ /* indexes: -+ * 0 = function (callback) -+ * 1 = delay -+ * 2 = boolean: oneshot -+ */ -+ -+ delay = duk_require_number(ctx, 1); -+ if (delay < MIN_DELAY) { -+ delay = MIN_DELAY; -+ } -+ oneshot = duk_require_boolean(ctx, 2); -+ -+ if (timer_count >= MAX_TIMERS) { -+ (void) duk_error(ctx, DUK_ERR_RANGE_ERROR, "out of timer slots"); -+ } -+ idx = timer_count++; -+ timer_id = timer_next_id++; -+ t = timer_list + idx; -+ -+ memset((void *) t, 0, sizeof(ev_timer)); -+ t->id = timer_id; -+ t->target = now + delay; -+ t->delay = delay; -+ t->oneshot = oneshot; -+ t->removed = 0; -+ -+ /* Timer is now at the last position; use swaps to "bubble" it to its -+ * correct sorted position. -+ */ -+ -+ bubble_last_timer(); -+ -+ /* Finally, register the callback to the global stash 'eventTimers' object. */ -+ -+ duk_push_global_stash(ctx); -+ duk_get_prop_string(ctx, -1, TIMERS_SLOT_NAME); /* -> [ func delay oneshot stash eventTimers ] */ -+ duk_push_number(ctx, (double) timer_id); -+ duk_dup(ctx, 0); -+ duk_put_prop(ctx, -3); /* eventTimers[timer_id] = callback */ -+ -+ /* Return timer id. */ -+ -+ duk_push_number(ctx, (double) timer_id); -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "created timer id: %d\n", (int) timer_id); -+ fflush(stderr); -+#endif -+ return 1; -+} -+ -+static int delete_timer(duk_context *ctx) { -+ int i, n; -+ int64_t timer_id; -+ ev_timer *t; -+ int found = 0; -+ -+ /* indexes: -+ * 0 = timer id -+ */ -+ -+ timer_id = (int64_t) duk_require_number(ctx, 0); -+ -+ /* -+ * Unlike insertion, deletion needs a full scan of the timer list -+ * and an expensive remove. If no match is found, nothing is deleted. -+ * Caller gets a boolean return code indicating match. -+ * -+ * When a timer is being expired and its user callback is running, -+ * the timer has been moved to 'timer_expiring' and its deletion -+ * needs special handling: just mark it to-be-deleted and let the -+ * expiry code remove it. -+ */ -+ -+ t = &timer_expiring; -+ if (t->id == timer_id) { -+ t->removed = 1; -+ duk_push_true(ctx); -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "deleted expiring timer id: %d\n", (int) timer_id); -+ fflush(stderr); -+#endif -+ return 1; -+ } -+ -+ n = timer_count; -+ for (i = 0; i < n; i++) { -+ t = timer_list + i; -+ if (t->id == timer_id) { -+ found = 1; -+ -+ /* Shift elements downwards to keep the timer list dense -+ * (no need if last element). -+ */ -+ if (i < timer_count - 1) { -+ memmove((void *) t, (void *) (t + 1), (timer_count - i - 1) * sizeof(ev_timer)); -+ } -+ -+ /* Zero last element for clarity. */ -+ memset((void *) (timer_list + n - 1), 0, sizeof(ev_timer)); -+ -+ /* Update timer_count. */ -+ timer_count--; -+ -+ /* The C state is now up-to-date, but we still need to delete -+ * the timer callback state from the global 'stash'. -+ */ -+ -+ duk_push_global_stash(ctx); -+ duk_get_prop_string(ctx, -1, TIMERS_SLOT_NAME); /* -> [ timer_id stash eventTimers ] */ -+ duk_push_number(ctx, (double) timer_id); -+ duk_del_prop(ctx, -2); /* delete eventTimers[timer_id] */ -+ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "deleted timer id: %d\n", (int) timer_id); -+ fflush(stderr); -+#endif -+ break; -+ } -+ } -+ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ if (!found) { -+ fprintf(stderr, "trying to delete timer id %d, but not found; ignoring\n", (int) timer_id); -+ fflush(stderr); -+ } -+#endif -+ -+ duk_push_boolean(ctx, found); -+ return 1; -+} -+ -+static int listen_fd(duk_context *ctx) { -+ int fd = duk_require_int(ctx, 0); -+ int events = duk_require_int(ctx, 1); -+ int i, n; -+ struct pollfd *pfd; -+ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "listen_fd: fd=%d, events=%d\n", fd, events); -+ fflush(stderr); -+#endif -+ /* events == 0 means stop listening to the FD */ -+ -+ n = poll_count; -+ for (i = 0; i < n; i++) { -+ pfd = poll_list + i; -+ if (pfd->fd == fd) { -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "listen_fd: fd found at index %d\n", i); -+ fflush(stderr); -+#endif -+ if (events == 0) { -+ /* mark to-be-deleted, cleaned up by next poll */ -+ pfd->fd = 0; -+ } else { -+ pfd->events = events; -+ } -+ return 0; -+ } -+ } -+ -+ /* not found, append to list */ -+#if DUKTAPE_EVENTLOOP_DEBUG > 0 -+ fprintf(stderr, "listen_fd: fd not found on list, add new entry\n"); -+ fflush(stderr); -+#endif -+ -+ if (poll_count >= MAX_FDS) { -+ (void) duk_error(ctx, DUK_ERR_ERROR, "out of fd slots"); -+ } -+ -+ pfd = poll_list + poll_count; -+ pfd->fd = fd; -+ pfd->events = events; -+ pfd->revents = 0; -+ poll_count++; -+ -+ return 0; -+} -+ -+static int request_exit(duk_context *ctx) { -+ (void) ctx; -+ exit_requested = 1; -+ return 0; -+} -+ -+static duk_function_list_entry eventloop_funcs[] = { -+ { "createTimer", create_timer, 3 }, -+ { "deleteTimer", delete_timer, 1 }, -+ { "listenFd", listen_fd, 2 }, -+ { "requestExit", request_exit, 0 }, -+ { NULL, NULL, 0 } -+}; -+ -+void eventloop_register(duk_context *ctx) { -+ memset((void *) timer_list, 0, MAX_TIMERS * sizeof(ev_timer)); -+ memset((void *) &timer_expiring, 0, sizeof(ev_timer)); -+ memset((void *) poll_list, 0, MAX_FDS * sizeof(struct pollfd)); -+ -+ /* Set global 'EventLoop'. */ -+ duk_push_global_object(ctx); -+ duk_push_object(ctx); -+ duk_put_function_list(ctx, -1, eventloop_funcs); -+ duk_put_prop_string(ctx, -2, "EventLoop"); -+ duk_pop(ctx); -+ -+ /* Initialize global stash 'eventTimers'. */ -+ duk_push_global_stash(ctx); -+ duk_push_object(ctx); -+ duk_put_prop_string(ctx, -2, TIMERS_SLOT_NAME); -+ duk_pop(ctx); -+} -diff --git a/dist/source/examples/eventloop/c_eventloop.h b/dist/source/examples/eventloop/c_eventloop.h -new file mode 100644 -index 0000000..719205f ---- /dev/null -+++ b/dist/source/examples/eventloop/c_eventloop.h -@@ -0,0 +1,7 @@ -+#if !defined(C_EVENTLOOP_H) -+#define C_EVENTLOOP_H -+ -+void eventloop_register(duk_context *ctx); -+duk_ret_t eventloop_run(duk_context *ctx, void *udata); -+ -+#endif -diff --git a/dist/source/examples/eventloop/c_eventloop.js b/dist/source/examples/eventloop/c_eventloop.js -new file mode 100644 -index 0000000..5b3c7c9 ---- /dev/null -+++ b/dist/source/examples/eventloop/c_eventloop.js -@@ -0,0 +1,192 @@ -+/* -+ * C eventloop example (c_eventloop.c). -+ * -+ * ECMAScript code to initialize the exposed API (setTimeout() etc) when -+ * using the C eventloop. -+ * -+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Timers -+ */ -+ -+/* -+ * Timer API -+ */ -+ -+function setTimeout(func, delay) { -+ var cb_func; -+ var bind_args; -+ var timer_id; -+ -+ // Delay can be optional at least in some contexts, so tolerate that. -+ // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout -+ if (typeof delay !== 'number') { -+ if (typeof delay === 'undefined') { -+ delay = 0; -+ } else { -+ throw new TypeError('invalid delay'); -+ } -+ } -+ -+ if (typeof func === 'string') { -+ // Legacy case: callback is a string. -+ cb_func = eval.bind(this, func); -+ } else if (typeof func !== 'function') { -+ throw new TypeError('callback is not a function/string'); -+ } else if (arguments.length > 2) { -+ // Special case: callback arguments are provided. -+ bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] -+ bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] -+ cb_func = func.bind.apply(func, bind_args); -+ } else { -+ // Normal case: callback given as a function without arguments. -+ cb_func = func; -+ } -+ -+ timer_id = EventLoop.createTimer(cb_func, delay, true /*oneshot*/); -+ -+ return timer_id; -+} -+ -+function clearTimeout(timer_id) { -+ if (typeof timer_id !== 'number') { -+ throw new TypeError('timer ID is not a number'); -+ } -+ var success = EventLoop.deleteTimer(timer_id); /* retval ignored */ -+} -+ -+function setInterval(func, delay) { -+ var cb_func; -+ var bind_args; -+ var timer_id; -+ -+ if (typeof delay !== 'number') { -+ if (typeof delay === 'undefined') { -+ delay = 0; -+ } else { -+ throw new TypeError('invalid delay'); -+ } -+ } -+ -+ if (typeof func === 'string') { -+ // Legacy case: callback is a string. -+ cb_func = eval.bind(this, func); -+ } else if (typeof func !== 'function') { -+ throw new TypeError('callback is not a function/string'); -+ } else if (arguments.length > 2) { -+ // Special case: callback arguments are provided. -+ bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] -+ bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] -+ cb_func = func.bind.apply(func, bind_args); -+ } else { -+ // Normal case: callback given as a function without arguments. -+ cb_func = func; -+ } -+ -+ timer_id = EventLoop.createTimer(cb_func, delay, false /*oneshot*/); -+ -+ return timer_id; -+} -+ -+function clearInterval(timer_id) { -+ if (typeof timer_id !== 'number') { -+ throw new TypeError('timer ID is not a number'); -+ } -+ EventLoop.deleteTimer(timer_id); -+} -+ -+function requestEventLoopExit() { -+ EventLoop.requestExit(); -+} -+ -+/* -+ * Socket handling -+ * -+ * Ideally this would be implemented more in C than here for more speed -+ * and smaller footprint: C code would directly maintain the callback state -+ * and such. -+ * -+ * Also for more optimal I/O, the buffer churn caused by allocating and -+ * freeing a lot of buffer values could be eliminated by reusing buffers. -+ * Socket reads would then go into a pre-allocated buffer, for instance. -+ */ -+ -+EventLoop.socketListening = {}; -+EventLoop.socketReading = {}; -+EventLoop.socketConnecting = {}; -+ -+EventLoop.fdPollHandler = function(fd, revents) { -+ var data; -+ var cb; -+ var rc; -+ var acc_res; -+ -+ //print('activity on fd', fd, 'revents', revents); -+ -+ if (revents & Poll.POLLIN) { -+ cb = this.socketReading[fd]; -+ if (cb) { -+ data = Socket.read(fd); // no size control now -+ //print('READ', Duktape.enc('jx', data)); -+ if (data.length === 0) { -+ this.close(fd); -+ return; -+ } -+ cb(fd, data); -+ } else { -+ cb = this.socketListening[fd]; -+ if (cb) { -+ acc_res = Socket.accept(fd); -+ //print('ACCEPT:', Duktape.enc('jx', acc_res)); -+ cb(acc_res.fd, acc_res.addr, acc_res.port); -+ } else { -+ //print('UNKNOWN'); -+ } -+ } -+ } -+ -+ if (revents & Poll.POLLOUT) { -+ // Connected -+ cb = this.socketConnecting[fd]; -+ if (cb) { -+ delete this.socketConnecting[fd]; -+ cb(fd); -+ } -+ } -+ -+ if ((revents & ~(Poll.POLLIN | Poll.POLLOUT)) !== 0) { -+ //print('unexpected revents, close fd'); -+ this.close(fd); -+ } -+} -+ -+EventLoop.server = function(address, port, cb_accepted) { -+ var fd = Socket.createServerSocket(address, port); -+ this.socketListening[fd] = cb_accepted; -+ this.listenFd(fd, Poll.POLLIN); -+} -+ -+EventLoop.connect = function(address, port, cb_connected) { -+ var fd = Socket.connect(address, port); -+ this.socketConnecting[fd] = cb_connected; -+ this.listenFd(fd, Poll.POLLOUT); -+} -+ -+EventLoop.close = function(fd) { -+ EventLoop.listenFd(fd, 0); -+ delete this.socketListening[fd]; -+ delete this.socketReading[fd]; -+ delete this.socketConnecting[fd]; -+ Socket.close(fd); -+} -+ -+EventLoop.setReader = function(fd, cb_read) { -+ this.socketReading[fd] = cb_read; -+ this.listenFd(fd, Poll.POLLIN); -+} -+ -+EventLoop.write = function(fd, data) { -+ // This simple example doesn't have support for write blocking / draining -+ if (typeof data === 'string') { -+ data = new TextEncoder().encode(data); -+ } -+ var rc = Socket.write(fd, data); -+} -diff --git a/dist/source/examples/eventloop/client-socket-test.js b/dist/source/examples/eventloop/client-socket-test.js -new file mode 100644 -index 0000000..d08b875 ---- /dev/null -+++ b/dist/source/examples/eventloop/client-socket-test.js -@@ -0,0 +1,16 @@ -+var HOST = 'localhost'; -+var PORT = 80; -+ -+EventLoop.connect(HOST, PORT, function (fd) { -+ print('connected to ' + HOST + ':' + PORT + ', fd', fd); -+ EventLoop.setReader(fd, function (fd, data) { -+ print('read from fd', fd); -+ print(new TextDecoder().decode(data)); -+ // Read until completion, socket is closed by server. -+ }); -+ EventLoop.write(fd, "GET / HTTP/1.1\r\n" + -+ "Host: " + HOST + "\r\n" + -+ "User-Agent: client-socket-test.js\r\n" + -+ "Connection: close\r\n" + -+ "\r\n"); -+}); -diff --git a/dist/source/examples/eventloop/ecma_eventloop.js b/dist/source/examples/eventloop/ecma_eventloop.js -new file mode 100644 -index 0000000..9ddd39d ---- /dev/null -+++ b/dist/source/examples/eventloop/ecma_eventloop.js -@@ -0,0 +1,478 @@ -+/* -+ * Pure ECMAScript eventloop example. -+ * -+ * Timer state handling is inefficient in this trivial example. Timers are -+ * kept in an array sorted by their expiry time which works well for expiring -+ * timers, but has O(n) insertion performance. A better implementation would -+ * use a heap or some other efficient structure for managing timers so that -+ * all operations (insert, remove, get nearest timer) have good performance. -+ * -+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Timers -+ */ -+ -+/* -+ * Event loop -+ * -+ * Timers are sorted by 'target' property which indicates expiry time of -+ * the timer. The timer expiring next is last in the array, so that -+ * removals happen at the end, and inserts for timers expiring in the -+ * near future displace as few elements in the array as possible. -+ */ -+ -+EventLoop = { -+ // timers -+ timers: [], // active timers, sorted (nearest expiry last) -+ expiring: null, // set to timer being expired (needs special handling in clearTimeout/clearInterval) -+ nextTimerId: 1, -+ minimumDelay: 1, -+ minimumWait: 1, -+ maximumWait: 60000, -+ maxExpirys: 10, -+ -+ // sockets -+ socketListening: {}, // fd -> callback -+ socketReading: {}, // fd -> callback -+ socketConnecting: {}, // fd -> callback -+ -+ // misc -+ exitRequested: false -+}; -+ -+EventLoop.dumpState = function() { -+ print('TIMER STATE:'); -+ this.timers.forEach(function(t) { -+ print(' ' + Duktape.enc('jx', t)); -+ }); -+ if (this.expiring) { -+ print(' EXPIRING: ' + Duktape.enc('jx', this.expiring)); -+ } -+} -+ -+// Get timer with lowest expiry time. Since the active timers list is -+// sorted, it's always the last timer. -+EventLoop.getEarliestTimer = function() { -+ var timers = this.timers; -+ n = timers.length; -+ return (n > 0 ? timers[n - 1] : null); -+} -+ -+EventLoop.getEarliestWait = function() { -+ var t = this.getEarliestTimer(); -+ return (t ? t.target - Date.now() : null); -+} -+ -+EventLoop.insertTimer = function(timer) { -+ var timers = this.timers; -+ var i, n, t; -+ -+ /* -+ * Find 'i' such that we want to insert *after* timers[i] at index i+1. -+ * If no such timer, for-loop terminates with i-1, and we insert at -1+1=0. -+ */ -+ -+ n = timers.length; -+ for (i = n - 1; i >= 0; i--) { -+ t = timers[i]; -+ if (timer.target <= t.target) { -+ // insert after 't', to index i+1 -+ break; -+ } -+ } -+ -+ timers.splice(i + 1 /*start*/, 0 /*deleteCount*/, timer); -+} -+ -+// Remove timer/interval with a timer ID. The timer/interval can reside -+// either on the active list or it may be an expired timer (this.expiring) -+// whose user callback we're running when this function gets called. -+EventLoop.removeTimerById = function(timer_id) { -+ var timers = this.timers; -+ var i, n, t; -+ -+ t = this.expiring; -+ if (t) { -+ if (t.id === timer_id) { -+ // Timer has expired and we're processing its callback. User -+ // callback has requested timer deletion. Mark removed, so -+ // that the timer is not reinserted back into the active list. -+ // This is actually a common case because an interval may very -+ // well cancel itself. -+ t.removed = true; -+ return; -+ } -+ } -+ -+ n = timers.length; -+ for (i = 0; i < n; i++) { -+ t = timers[i]; -+ if (t.id === timer_id) { -+ // Timer on active list: mark removed (not really necessary, but -+ // nice for dumping), and remove from active list. -+ t.removed = true; -+ this.timers.splice(i /*start*/, 1 /*deleteCount*/); -+ return; -+ } -+ } -+ -+ // no such ID, ignore -+} -+ -+EventLoop.processTimers = function() { -+ var now = Date.now(); -+ var timers = this.timers; -+ var sanity = this.maxExpirys; -+ var n, t; -+ -+ /* -+ * Here we must be careful with mutations: user callback may add and -+ * delete an arbitrary number of timers. -+ * -+ * Current solution is simple: check whether the timer at the end of -+ * the list has expired. If not, we're done. If it has expired, -+ * remove it from the active list, record it in this.expiring, and call -+ * the user callback. If user code deletes the this.expiring timer, -+ * there is special handling which just marks the timer deleted so -+ * it won't get inserted back into the active list. -+ * -+ * This process is repeated at most maxExpirys times to ensure we don't -+ * get stuck forever; user code could in principle add more and more -+ * already expired timers. -+ */ -+ -+ while (sanity-- > 0) { -+ // If exit requested, don't call any more callbacks. This allows -+ // a callback to do cleanups and request exit, and can be sure that -+ // no more callbacks are processed. -+ -+ if (this.exitRequested) { -+ //print('exit requested, exit'); -+ break; -+ } -+ -+ // Timers to expire? -+ -+ n = timers.length; -+ if (n <= 0) { -+ break; -+ } -+ t = timers[n - 1]; -+ if (now <= t.target) { -+ // Timer has not expired, and no other timer could have expired -+ // either because the list is sorted. -+ break; -+ } -+ timers.pop(); -+ -+ // Remove the timer from the active list and process it. The user -+ // callback may add new timers which is not a problem. The callback -+ // may also delete timers which is not a problem unless the timer -+ // being deleted is the timer whose callback we're running; this is -+ // why the timer is recorded in this.expiring so that clearTimeout() -+ // and clearInterval() can detect this situation. -+ -+ if (t.oneshot) { -+ t.removed = true; // flag for removal -+ } else { -+ t.target = now + t.delay; -+ } -+ this.expiring = t; -+ try { -+ t.cb(); -+ } catch (e) { -+ print('timer callback failed, ignored: ' + e); -+ } -+ this.expiring = null; -+ -+ // If the timer was one-shot, it's marked 'removed'. If the user callback -+ // requested deletion for the timer, it's also marked 'removed'. If the -+ // timer is an interval (and is not marked removed), insert it back into -+ // the timer list. -+ -+ if (!t.removed) { -+ // Reinsert interval timer to correct sorted position. The timer -+ // must be an interval timer because one-shot timers are marked -+ // 'removed' above. -+ this.insertTimer(t); -+ } -+ } -+} -+ -+EventLoop.run = function() { -+ var wait; -+ var POLLIN = Poll.POLLIN; -+ var POLLOUT = Poll.POLLOUT; -+ var poll_set; -+ var poll_count; -+ var fd; -+ var t, rev; -+ var rc; -+ var acc_res; -+ -+ for (;;) { -+ /* -+ * Process expired timers. -+ */ -+ -+ this.processTimers(); -+ //this.dumpState(); -+ -+ /* -+ * Exit check (may be requested by a user callback) -+ */ -+ -+ if (this.exitRequested) { -+ //print('exit requested, exit'); -+ break; -+ } -+ -+ /* -+ * Create poll socket list. This is a very naive approach. -+ * On Linux, one could use e.g. epoll() and manage socket lists -+ * incrementally. -+ */ -+ -+ poll_set = {}; -+ poll_count = 0; -+ for (fd in this.socketListening) { -+ poll_set[fd] = { events: POLLIN, revents: 0 }; -+ poll_count++; -+ } -+ for (fd in this.socketReading) { -+ poll_set[fd] = { events: POLLIN, revents: 0 }; -+ poll_count++; -+ } -+ for (fd in this.socketConnecting) { -+ poll_set[fd] = { events: POLLOUT, revents: 0 }; -+ poll_count++; -+ } -+ //print(new Date(), 'poll_set IN:', Duktape.enc('jx', poll_set)); -+ -+ /* -+ * Wait timeout for timer closest to expiry. Since the poll -+ * timeout is relative, get this as close to poll() as possible. -+ */ -+ -+ wait = this.getEarliestWait(); -+ if (wait === null) { -+ if (poll_count === 0) { -+ print('no active timers and no sockets to poll, exit'); -+ break; -+ } else { -+ wait = this.maximumWait; -+ } -+ } else { -+ wait = Math.min(this.maximumWait, Math.max(this.minimumWait, wait)); -+ } -+ -+ /* -+ * Do the actual poll. -+ */ -+ -+ try { -+ Poll.poll(poll_set, wait); -+ } catch (e) { -+ // Eat errors silently. -+ } -+ -+ /* -+ * Process all sockets so that nothing is left unhandled for the -+ * next round. -+ */ -+ -+ //print(new Date(), 'poll_set OUT:', Duktape.enc('jx', poll_set)); -+ for (fd in poll_set) { -+ t = poll_set[fd]; -+ rev = t.revents; -+ -+ if (rev & POLLIN) { -+ cb = this.socketReading[fd]; -+ if (cb) { -+ data = Socket.read(fd); // no size control now -+ //print('READ', Duktape.enc('jx', data)); -+ if (data.length === 0) { -+ //print('zero read for fd ' + fd + ', closing forcibly'); -+ rc = Socket.close(fd); // ignore result -+ delete this.socketListening[fd]; -+ delete this.socketReading[fd]; -+ } else { -+ cb(fd, data); -+ } -+ } else { -+ cb = this.socketListening[fd]; -+ if (cb) { -+ acc_res = Socket.accept(fd); -+ //print('ACCEPT:', Duktape.enc('jx', acc_res)); -+ cb(acc_res.fd, acc_res.addr, acc_res.port); -+ } else { -+ //print('UNKNOWN'); -+ } -+ } -+ } -+ -+ if (rev & POLLOUT) { -+ cb = this.socketConnecting[fd]; -+ if (cb) { -+ delete this.socketConnecting[fd]; -+ cb(fd); -+ } else { -+ //print('UNKNOWN POLLOUT'); -+ } -+ } -+ -+ if ((rev & ~(POLLIN | POLLOUT)) !== 0) { -+ //print('revents ' + t.revents + ' for fd ' + fd + ', closing forcibly'); -+ rc = Socket.close(fd); // ignore result -+ delete this.socketListening[fd]; -+ delete this.socketReading[fd]; -+ } -+ } -+ } -+} -+ -+EventLoop.requestExit = function() { -+ this.exitRequested = true; -+} -+ -+EventLoop.server = function(address, port, cb_accepted) { -+ var fd = Socket.createServerSocket(address, port); -+ this.socketListening[fd] = cb_accepted; -+} -+ -+EventLoop.connect = function(address, port, cb_connected) { -+ var fd = Socket.connect(address, port); -+ this.socketConnecting[fd] = cb_connected; -+} -+ -+EventLoop.close = function(fd) { -+ delete this.socketReading[fd]; -+ delete this.socketListening[fd]; -+} -+ -+EventLoop.setReader = function(fd, cb_read) { -+ this.socketReading[fd] = cb_read; -+} -+ -+EventLoop.write = function(fd, data) { -+ // This simple example doesn't have support for write blocking / draining -+ if (typeof data === 'string') { -+ data = new TextEncoder().encode(data); -+ } -+ var rc = Socket.write(fd, data); -+} -+ -+/* -+ * Timer API -+ * -+ * These interface with the singleton EventLoop. -+ */ -+ -+function setTimeout(func, delay) { -+ var cb_func; -+ var bind_args; -+ var timer_id; -+ var evloop = EventLoop; -+ -+ // Delay can be optional at least in some contexts, so tolerate that. -+ // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout -+ if (typeof delay !== 'number') { -+ if (typeof delay === 'undefined') { -+ delay = 0; -+ } else { -+ throw new TypeError('invalid delay'); -+ } -+ } -+ delay = Math.max(evloop.minimumDelay, delay); -+ -+ if (typeof func === 'string') { -+ // Legacy case: callback is a string. -+ cb_func = eval.bind(this, func); -+ } else if (typeof func !== 'function') { -+ throw new TypeError('callback is not a function/string'); -+ } else if (arguments.length > 2) { -+ // Special case: callback arguments are provided. -+ bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] -+ bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] -+ cb_func = func.bind.apply(func, bind_args); -+ } else { -+ // Normal case: callback given as a function without arguments. -+ cb_func = func; -+ } -+ -+ timer_id = evloop.nextTimerId++; -+ -+ evloop.insertTimer({ -+ id: timer_id, -+ oneshot: true, -+ cb: cb_func, -+ delay: delay, -+ target: Date.now() + delay -+ }); -+ -+ return timer_id; -+} -+ -+function clearTimeout(timer_id) { -+ var evloop = EventLoop; -+ -+ if (typeof timer_id !== 'number') { -+ throw new TypeError('timer ID is not a number'); -+ } -+ evloop.removeTimerById(timer_id); -+} -+ -+function setInterval(func, delay) { -+ var cb_func; -+ var bind_args; -+ var timer_id; -+ var evloop = EventLoop; -+ -+ if (typeof delay !== 'number') { -+ if (typeof delay === 'undefined') { -+ delay = 0; -+ } else { -+ throw new TypeError('invalid delay'); -+ } -+ } -+ delay = Math.max(evloop.minimumDelay, delay); -+ -+ if (typeof func === 'string') { -+ // Legacy case: callback is a string. -+ cb_func = eval.bind(this, func); -+ } else if (typeof func !== 'function') { -+ throw new TypeError('callback is not a function/string'); -+ } else if (arguments.length > 2) { -+ // Special case: callback arguments are provided. -+ bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] -+ bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] -+ cb_func = func.bind.apply(func, bind_args); -+ } else { -+ // Normal case: callback given as a function without arguments. -+ cb_func = func; -+ } -+ -+ timer_id = evloop.nextTimerId++; -+ -+ evloop.insertTimer({ -+ id: timer_id, -+ oneshot: false, -+ cb: cb_func, -+ delay: delay, -+ target: Date.now() + delay -+ }); -+ -+ return timer_id; -+} -+ -+function clearInterval(timer_id) { -+ var evloop = EventLoop; -+ -+ if (typeof timer_id !== 'number') { -+ throw new TypeError('timer ID is not a number'); -+ } -+ evloop.removeTimerById(timer_id); -+} -+ -+/* custom call */ -+function requestEventLoopExit() { -+ EventLoop.requestExit(); -+} -diff --git a/dist/source/examples/eventloop/fileio.c b/dist/source/examples/eventloop/fileio.c -new file mode 100644 -index 0000000..974e2d7 ---- /dev/null -+++ b/dist/source/examples/eventloop/fileio.c -@@ -0,0 +1,84 @@ -+/* -+ * File I/O binding example. -+ */ -+ -+#include -+#include -+#include -+ -+#include "duktape.h" -+ -+/* Push file as a buffer. */ -+void fileio_push_file_buffer(duk_context *ctx, const char *filename) { -+ FILE *f = NULL; -+ long len; -+ void *buf; -+ size_t got; -+ -+ if (!filename) { -+ goto error; -+ } -+ -+ f = fopen(filename, "rb"); -+ if (!f) { -+ goto error; -+ } -+ -+ if (fseek(f, 0, SEEK_END) != 0) { -+ goto error; -+ } -+ -+ len = ftell(f); -+ -+ if (fseek(f, 0, SEEK_SET) != 0) { -+ goto error; -+ } -+ -+ buf = duk_push_fixed_buffer(ctx, (size_t) len); -+ -+ got = fread(buf, 1, len, f); -+ if (got != (size_t) len) { -+ duk_pop(ctx); -+ goto error; -+ } -+ -+ fclose(f); -+ return; -+ -+ error: -+ if (f) { -+ fclose(f); -+ } -+ duk_push_undefined(ctx); -+} -+ -+/* Push file as a string. */ -+void fileio_push_file_string(duk_context *ctx, const char *filename) { -+ fileio_push_file_buffer(ctx, filename); -+ if (duk_is_buffer_data(ctx, -1)) { -+ duk_buffer_to_string(ctx, -1); -+ } -+} -+ -+static int fileio_readfile(duk_context *ctx) { -+ const char *filename = duk_to_string(ctx, 0); -+ fileio_push_file_buffer(ctx, filename); -+ if (!duk_is_buffer_data(ctx, -1)) { -+ return DUK_RET_ERROR; -+ } -+ return 1; -+} -+ -+static duk_function_list_entry fileio_funcs[] = { -+ { "readfile", fileio_readfile, 1 }, -+ { NULL, NULL, 0 } -+}; -+ -+void fileio_register(duk_context *ctx) { -+ /* Set global 'FileIo'. */ -+ duk_push_global_object(ctx); -+ duk_push_object(ctx); -+ duk_put_function_list(ctx, -1, fileio_funcs); -+ duk_put_prop_string(ctx, -2, "FileIo"); -+ duk_pop(ctx); -+} -diff --git a/dist/source/examples/eventloop/main.c b/dist/source/examples/eventloop/main.c -new file mode 100644 -index 0000000..d09828f ---- /dev/null -+++ b/dist/source/examples/eventloop/main.c -@@ -0,0 +1,286 @@ -+/* -+ * Main for evloop command line tool. -+ * -+ * Runs a given script from file or stdin inside an eventloop. The -+ * script can then access setTimeout() etc. -+ */ -+ -+#include -+#include -+#include -+#if !defined(NO_SIGNAL) -+#include -+#endif -+ -+#include "duktape.h" -+ -+extern void poll_register(duk_context *ctx); -+extern void socket_register(duk_context *ctx); -+extern void fileio_register(duk_context *ctx); -+extern void fileio_push_file_buffer(duk_context *ctx, const char *filename); -+extern void fileio_push_file_string(duk_context *ctx, const char *filename); -+extern void eventloop_register(duk_context *ctx); -+extern duk_ret_t eventloop_run(duk_context *ctx, void *udata); -+ -+static int c_evloop = 0; -+ -+#if !defined(NO_SIGNAL) -+static void my_sighandler(int x) { -+ fprintf(stderr, "Got signal %d\n", x); -+ fflush(stderr); -+} -+static void set_sigint_handler(void) { -+ (void) signal(SIGINT, my_sighandler); -+} -+#endif /* NO_SIGNAL */ -+ -+/* Print error to stderr and pop error. */ -+static void print_error(duk_context *ctx, FILE *f) { -+ if (duk_is_object(ctx, -1) && duk_has_prop_string(ctx, -1, "stack")) { -+ /* XXX: print error objects specially */ -+ /* XXX: pcall the string coercion */ -+ duk_get_prop_string(ctx, -1, "stack"); -+ if (duk_is_string(ctx, -1)) { -+ fprintf(f, "%s\n", duk_get_string(ctx, -1)); -+ fflush(f); -+ duk_pop_2(ctx); -+ return; -+ } else { -+ duk_pop(ctx); -+ } -+ } -+ duk_to_string(ctx, -1); -+ fprintf(f, "%s\n", duk_get_string(ctx, -1)); -+ fflush(f); -+ duk_pop(ctx); -+} -+ -+static duk_ret_t native_print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ return 0; -+} -+ -+static void print_register(duk_context *ctx) { -+ duk_push_c_function(ctx, native_print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+} -+ -+static duk_ret_t wrapped_compile_execute(duk_context *ctx, void *udata) { -+ int comp_flags = 0; -+ int rc; -+ -+ (void) udata; -+ -+ /* Compile input and place it into global _USERCODE */ -+ duk_compile(ctx, comp_flags); -+ duk_push_global_object(ctx); -+ duk_insert(ctx, -2); /* [ ... global func ] */ -+ duk_put_prop_string(ctx, -2, "_USERCODE"); -+ duk_pop(ctx); -+#if 0 -+ printf("compiled usercode\n"); -+#endif -+ -+ /* Start a zero timer which will call _USERCODE from within -+ * the event loop. -+ */ -+ fprintf(stderr, "set _USERCODE timer\n"); -+ fflush(stderr); -+ duk_eval_string(ctx, "setTimeout(function() { _USERCODE(); }, 0);"); -+ duk_pop(ctx); -+ -+ /* Finally, launch eventloop. This call only returns after the -+ * eventloop terminates. -+ */ -+ if (c_evloop) { -+ fprintf(stderr, "calling eventloop_run()\n"); -+ fflush(stderr); -+ rc = duk_safe_call(ctx, eventloop_run, NULL, 0 /*nargs*/, 1 /*nrets*/); -+ if (rc != 0) { -+ fprintf(stderr, "eventloop_run() failed: %s\n", duk_to_string(ctx, -1)); -+ fflush(stderr); -+ } -+ duk_pop(ctx); -+ } else { -+ fprintf(stderr, "calling EventLoop.run()\n"); -+ fflush(stderr); -+ duk_eval_string(ctx, "EventLoop.run();"); -+ duk_pop(ctx); -+ } -+ -+ return 0; -+} -+ -+static int handle_fh(duk_context *ctx, FILE *f, const char *filename) { -+ char *buf = NULL; -+ int len; -+ int got; -+ int rc; -+ int retval = -1; -+ -+ if (fseek(f, 0, SEEK_END) < 0) { -+ goto error; -+ } -+ len = (int) ftell(f); -+ if (fseek(f, 0, SEEK_SET) < 0) { -+ goto error; -+ } -+ buf = (char *) malloc(len); -+ if (!buf) { -+ goto error; -+ } -+ -+ got = fread((void *) buf, (size_t) 1, (size_t) len, f); -+ -+ duk_push_lstring(ctx, buf, got); -+ duk_push_string(ctx, filename); -+ -+ free(buf); -+ buf = NULL; -+ -+ rc = duk_safe_call(ctx, wrapped_compile_execute, NULL, 2 /*nargs*/, 1 /*nret*/); -+ if (rc != DUK_EXEC_SUCCESS) { -+ print_error(ctx, stderr); -+ goto error; -+ } else { -+ duk_pop(ctx); -+ retval = 0; -+ } -+ /* fall thru */ -+ -+ error: -+ if (buf) { -+ free(buf); -+ } -+ return retval; -+} -+ -+static int handle_file(duk_context *ctx, const char *filename) { -+ FILE *f = NULL; -+ int retval; -+ -+ f = fopen(filename, "rb"); -+ if (!f) { -+ fprintf(stderr, "failed to open source file: %s\n", filename); -+ fflush(stderr); -+ goto error; -+ } -+ -+ retval = handle_fh(ctx, f, filename); -+ -+ fclose(f); -+ return retval; -+ -+ error: -+ return -1; -+} -+ -+static int handle_stdin(duk_context *ctx) { -+ int retval; -+ -+ retval = handle_fh(ctx, stdin, "stdin"); -+ -+ return retval; -+} -+ -+static duk_ret_t init_duktape_context(duk_context *ctx, void *udata) { -+ (void) udata; -+ -+ print_register(ctx); -+ poll_register(ctx); -+ socket_register(ctx); -+ fileio_register(ctx); -+ -+ if (c_evloop) { -+ fprintf(stderr, "Using C based eventloop (omit -c to use ECMAScript based eventloop)\n"); -+ fflush(stderr); -+ -+ eventloop_register(ctx); -+ fileio_push_file_string(ctx, "c_eventloop.js"); -+ duk_eval(ctx); -+ } else { -+ fprintf(stderr, "Using ECMAScript based eventloop (give -c to use C based eventloop)\n"); -+ fflush(stderr); -+ -+ fileio_push_file_string(ctx, "ecma_eventloop.js"); -+ duk_eval(ctx); -+ } -+ -+ return 0; -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx = NULL; -+ int retval = 1; -+ const char *filename = NULL; -+ int i; -+ -+#if !defined(NO_SIGNAL) -+ set_sigint_handler(); -+ -+ /* This is useful at the global level; libraries should avoid SIGPIPE though */ -+ /*signal(SIGPIPE, SIG_IGN);*/ -+#endif -+ -+ for (i = 1; i < argc; i++) { -+ char *arg = argv[i]; -+ if (!arg) { -+ goto usage; -+ } -+ if (strcmp(arg, "-c") == 0) { -+ c_evloop = 1; -+ } else if (strlen(arg) > 1 && arg[0] == '-') { -+ goto usage; -+ } else { -+ if (filename) { -+ goto usage; -+ } -+ filename = arg; -+ } -+ } -+ if (!filename) { -+ goto usage; -+ } -+ -+ ctx = duk_create_heap_default(); -+ -+ if (duk_safe_call(ctx, init_duktape_context, NULL, 0 /*nargs*/, 1 /*nrets*/) != 0) { -+ fprintf(stderr, "Failed to initialize: %s\n", duk_safe_to_string(ctx, -1)); -+ goto cleanup; -+ } -+ duk_pop(ctx); -+ -+ fprintf(stderr, "Executing code from: '%s'\n", filename); -+ fflush(stderr); -+ -+ if (strcmp(filename, "-") == 0) { -+ if (handle_stdin(ctx) != 0) { -+ goto cleanup; -+ } -+ } else { -+ if (handle_file(ctx, filename) != 0) { -+ goto cleanup; -+ } -+ } -+ -+ retval = 0; -+ /* fall through */ -+ cleanup: -+ if (ctx) { -+ duk_destroy_heap(ctx); -+ } -+ -+ return retval; -+ -+ usage: -+ fprintf(stderr, "Usage: evloop [-c] \n"); -+ fprintf(stderr, "\n"); -+ fprintf(stderr, "Uses an ECMAScript based eventloop (ecma_eventloop.js) by default.\n"); -+ fprintf(stderr, "If -c option given, uses a C based eventloop (c_eventloop.{c,js}).\n"); -+ fprintf(stderr, "If is '-', the entire STDIN executed.\n"); -+ fflush(stderr); -+ exit(1); -+} -diff --git a/dist/source/examples/eventloop/poll.c b/dist/source/examples/eventloop/poll.c -new file mode 100644 -index 0000000..330bb6f ---- /dev/null -+++ b/dist/source/examples/eventloop/poll.c -@@ -0,0 +1,119 @@ -+/* -+ * C wrapper for poll(). -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+ -+#if defined(_WIN32) -+#include -+#define poll WSAPoll -+#pragma comment(lib, "ws2_32") -+#else -+#include -+#endif -+ -+#include -+ -+#include "duktape.h" -+ -+static int poll_poll(duk_context *ctx) { -+ int timeout = duk_to_int(ctx, 1); -+ int i, n, nchanged; -+ int fd, rc; -+ struct pollfd fds[20]; -+ struct timespec ts; -+ -+ memset(fds, 0, sizeof(fds)); -+ -+ n = 0; -+ duk_enum(ctx, 0, 0 /*enum_flags*/); -+ while (duk_next(ctx, -1, 0)) { -+ if ((size_t) n >= sizeof(fds) / sizeof(struct pollfd)) { -+ return -1; -+ } -+ -+ /* [... enum key] */ -+ duk_dup_top(ctx); /* -> [... enum key key] */ -+ duk_get_prop(ctx, 0); /* -> [... enum key val] */ -+ fd = duk_to_int(ctx, -2); -+ -+ duk_push_string(ctx, "events"); -+ duk_get_prop(ctx, -2); /* -> [... enum key val events] */ -+ -+ fds[n].fd = fd; -+ fds[n].events = duk_to_int(ctx, -1); -+ fds[n].revents = 0; -+ -+ duk_pop_n(ctx, 3); /* -> [... enum] */ -+ -+ n++; -+ } -+ /* leave enum on stack */ -+ -+ memset(&ts, 0, sizeof(ts)); -+ ts.tv_nsec = (timeout % 1000) * 1000000; -+ ts.tv_sec = timeout / 1000; -+ -+ /*rc = ppoll(fds, n, &ts, NULL);*/ -+ rc = poll(fds, n, timeout); -+ if (rc < 0) { -+ (void) duk_error(ctx, DUK_ERR_ERROR, "%s (errno=%d)", strerror(errno), errno); -+ } -+ -+ duk_push_array(ctx); -+ nchanged = 0; -+ for (i = 0; i < n; i++) { -+ /* update revents */ -+ -+ if (fds[i].revents) { -+ duk_push_int(ctx, fds[i].fd); /* -> [... retarr fd] */ -+ duk_put_prop_index(ctx, -2, nchanged); -+ nchanged++; -+ } -+ -+ duk_push_int(ctx, fds[i].fd); /* -> [... retarr key] */ -+ duk_get_prop(ctx, 0); /* -> [... retarr val] */ -+ duk_push_string(ctx, "revents"); -+ duk_push_int(ctx, fds[i].revents); /* -> [... retarr val "revents" fds[i].revents] */ -+ duk_put_prop(ctx, -3); /* -> [... retarr val] */ -+ duk_pop(ctx); -+ } -+ -+ /* [retarr] */ -+ -+ return 1; -+} -+ -+static duk_function_list_entry poll_funcs[] = { -+ { "poll", poll_poll, 2 }, -+ { NULL, NULL, 0 } -+}; -+ -+static duk_number_list_entry poll_consts[] = { -+ { "POLLIN", (double) POLLIN }, -+ { "POLLPRI", (double) POLLPRI }, -+ { "POLLOUT", (double) POLLOUT }, -+#if 0 -+ /* Linux 2.6.17 and upwards, requires _GNU_SOURCE etc, not added -+ * now because we don't use it. -+ */ -+ { "POLLRDHUP", (double) POLLRDHUP }, -+#endif -+ { "POLLERR", (double) POLLERR }, -+ { "POLLHUP", (double) POLLHUP }, -+ { "POLLNVAL", (double) POLLNVAL }, -+ { NULL, 0.0 } -+}; -+ -+void poll_register(duk_context *ctx) { -+ /* Set global 'Poll' with functions and constants. */ -+ duk_push_global_object(ctx); -+ duk_push_object(ctx); -+ duk_put_function_list(ctx, -1, poll_funcs); -+ duk_put_number_list(ctx, -1, poll_consts); -+ duk_put_prop_string(ctx, -2, "Poll"); -+ duk_pop(ctx); -+} -diff --git a/dist/source/examples/eventloop/server-socket-test.js b/dist/source/examples/eventloop/server-socket-test.js -new file mode 100644 -index 0000000..e3c0086 ---- /dev/null -+++ b/dist/source/examples/eventloop/server-socket-test.js -@@ -0,0 +1,33 @@ -+var HOST = 'localhost' -+var PORT = 12345; -+var EXIT_TIMEOUT = 300e3; -+ -+print('automatic exit after ' + (EXIT_TIMEOUT / 1e3) + ' seconds'); -+setTimeout(function () { -+ print('exit timer'); -+ EventLoop.requestExit(); -+}, EXIT_TIMEOUT); -+ -+print('listen on ' + HOST + ':' + PORT); -+EventLoop.server(HOST, PORT, function (fd, addr, port) { -+ print('new connection on fd ' + fd + ' from ' + addr + ':' + port); -+ EventLoop.setReader(fd, function (fd, data) { -+ var b, i, n, x; -+ -+ // Handle socket data carefully: if you convert it to a string, -+ // it may not be valid UTF-8 etc. Here we operate on the data -+ // directly in the buffer. -+ -+ b = data.valueOf(); // ensure we get a plain buffer -+ n = b.length; -+ for (i = 0; i < n; i++) { -+ x = b[i]; -+ if (x >= 0x61 && x <= 0x7a) { -+ b[i] = x - 0x20; // uppercase -+ } -+ } -+ -+ print('read data on fd ' + fd + ', length ' + data.length); -+ EventLoop.write(fd, data); -+ }); -+}); -diff --git a/dist/source/examples/eventloop/socket.c b/dist/source/examples/eventloop/socket.c -new file mode 100644 -index 0000000..9c391fa ---- /dev/null -+++ b/dist/source/examples/eventloop/socket.c -@@ -0,0 +1,286 @@ -+/* -+ * TCP sockets binding example. -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "duktape.h" -+ -+#define ERROR_FROM_ERRNO(ctx) do { \ -+ (void) duk_error(ctx, DUK_ERR_ERROR, "%s (errno=%d)", strerror(errno), errno); \ -+ } while (0) -+ -+static void set_nonblocking(duk_context *ctx, int fd) { -+ int rc; -+ int flags; -+ -+ rc = fcntl(fd, F_GETFL); -+ if (rc < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ flags = rc; -+ -+ flags |= O_NONBLOCK; -+ -+ rc = fcntl(fd, F_SETFL, flags); -+ if (rc < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+} -+ -+static void set_reuseaddr(duk_context *ctx, int fd) { -+ int val; -+ int rc; -+ -+ val = 1; -+ rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &val, sizeof(val)); -+ if (rc != 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+} -+ -+#if defined(__APPLE__) -+static void set_nosigpipe(duk_context *ctx, int fd) { -+ int val; -+ int rc; -+ -+ val = 1; -+ rc = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &val, sizeof(val)); -+ if (rc != 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+} -+#endif -+ -+static int socket_create_server_socket(duk_context *ctx) { -+ const char *addr = duk_to_string(ctx, 0); -+ int port = duk_to_int(ctx, 1); -+ int sock; -+ struct sockaddr_in sockaddr; -+ struct hostent *ent; -+ struct in_addr **addr_list; -+ struct in_addr *addr_inet; -+ int i; -+ int rc; -+ -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ if (sock < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ set_nonblocking(ctx, sock); -+ set_reuseaddr(ctx, sock); -+#if defined(__APPLE__) -+ set_nosigpipe(ctx, sock); -+#endif -+ -+ ent = gethostbyname(addr); -+ if (!ent) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ addr_list = (struct in_addr **) ent->h_addr_list; -+ addr_inet = NULL; -+ for (i = 0; addr_list[i]; i++) { -+ addr_inet = addr_list[i]; -+ break; -+ } -+ if (!addr_inet) { -+ (void) duk_error(ctx, DUK_ERR_ERROR, "cannot resolve %s", addr); -+ } -+ -+ memset(&sockaddr, 0, sizeof(sockaddr)); -+ sockaddr.sin_family = AF_INET; -+ sockaddr.sin_port = htons(port); -+ sockaddr.sin_addr = *addr_inet; -+ -+ rc = bind(sock, (const struct sockaddr *) &sockaddr, sizeof(sockaddr)); -+ if (rc < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ rc = listen(sock, 10 /*backlog*/); -+ if (rc < 0) { -+ (void) close(sock); -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ duk_push_int(ctx, sock); -+ return 1; -+} -+ -+static int socket_close(duk_context *ctx) { -+ int sock = duk_to_int(ctx, 0); -+ int rc; -+ -+ rc = close(sock); -+ if (rc < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ return 0; -+} -+ -+static int socket_accept(duk_context *ctx) { -+ int sock = duk_to_int(ctx, 0); -+ int rc; -+ struct sockaddr_in addr; -+ socklen_t addrlen; -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.sin_family = AF_INET; -+ addrlen = sizeof(addr); -+ -+ rc = accept(sock, (struct sockaddr *) &addr, &addrlen); -+ if (rc < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ set_nonblocking(ctx, sock); -+#if defined(__APPLE__) -+ set_nosigpipe(ctx, sock); -+#endif -+ -+ if (addrlen == sizeof(addr)) { -+ uint32_t tmp = ntohl(addr.sin_addr.s_addr); -+ -+ duk_push_object(ctx); -+ -+ duk_push_string(ctx, "fd"); -+ duk_push_int(ctx, rc); -+ duk_put_prop(ctx, -3); -+ duk_push_string(ctx, "addr"); -+ duk_push_sprintf(ctx, "%d.%d.%d.%d", ((tmp >> 24) & 0xff), ((tmp >> 16) & 0xff), ((tmp >> 8) & 0xff), (tmp & 0xff)); -+ duk_put_prop(ctx, -3); -+ duk_push_string(ctx, "port"); -+ duk_push_int(ctx, ntohs(addr.sin_port)); -+ duk_put_prop(ctx, -3); -+ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static int socket_connect(duk_context *ctx) { -+ const char *addr = duk_to_string(ctx, 0); -+ int port = duk_to_int(ctx, 1); -+ int sock; -+ struct sockaddr_in sockaddr; -+ struct hostent *ent; -+ struct in_addr **addr_list; -+ struct in_addr *addr_inet; -+ int i; -+ int rc; -+ -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ if (sock < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ set_nonblocking(ctx, sock); -+#if defined(__APPLE__) -+ set_nosigpipe(ctx, sock); -+#endif -+ -+ ent = gethostbyname(addr); -+ if (!ent) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ addr_list = (struct in_addr **) ent->h_addr_list; -+ addr_inet = NULL; -+ for (i = 0; addr_list[i]; i++) { -+ addr_inet = addr_list[i]; -+ break; -+ } -+ if (!addr_inet) { -+ (void) duk_error(ctx, DUK_ERR_ERROR, "cannot resolve %s", addr); -+ } -+ -+ memset(&sockaddr, 0, sizeof(sockaddr)); -+ sockaddr.sin_family = AF_INET; -+ sockaddr.sin_port = htons(port); -+ sockaddr.sin_addr = *addr_inet; -+ -+ rc = connect(sock, (const struct sockaddr *) &sockaddr, (socklen_t) sizeof(sockaddr)); -+ if (rc < 0) { -+ if (errno == EINPROGRESS) { -+#if 0 -+ fprintf(stderr, "connect() returned EINPROGRESS as expected, need to poll writability\n"); -+ fflush(stderr); -+#endif -+ } else { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ } -+ -+ duk_push_int(ctx, sock); -+ return 1; -+} -+ -+static int socket_read(duk_context *ctx) { -+ int sock = duk_to_int(ctx, 0); -+ char readbuf[1024]; -+ int rc; -+ void *data; -+ -+ rc = recvfrom(sock, (void *) readbuf, sizeof(readbuf), 0, NULL, NULL); -+ if (rc < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ data = duk_push_fixed_buffer(ctx, rc); -+ memcpy(data, readbuf, rc); -+ return 1; -+} -+ -+static int socket_write(duk_context *ctx) { -+ int sock = duk_to_int(ctx, 0); -+ const char *data; -+ size_t len; -+ ssize_t rc; -+ -+ data = duk_require_buffer_data(ctx, 1, &len); -+ -+ /* MSG_NOSIGNAL: avoid SIGPIPE */ -+#if defined(__APPLE__) -+ rc = sendto(sock, (void *) data, len, 0, NULL, 0); -+#else -+ rc = sendto(sock, (void *) data, len, MSG_NOSIGNAL, NULL, 0); -+#endif -+ if (rc < 0) { -+ ERROR_FROM_ERRNO(ctx); -+ } -+ -+ duk_push_int(ctx, rc); -+ return 1; -+} -+ -+static duk_function_list_entry socket_funcs[] = { -+ { "createServerSocket", socket_create_server_socket, 2 }, -+ { "close", socket_close, 1 }, -+ { "accept", socket_accept, 1 }, -+ { "connect", socket_connect, 2 }, -+ { "read", socket_read, 1 }, -+ { "write", socket_write, 2 }, -+ { NULL, NULL, 0 } -+}; -+ -+void socket_register(duk_context *ctx) { -+ /* Set global 'Socket'. */ -+ duk_push_global_object(ctx); -+ duk_push_object(ctx); -+ duk_put_function_list(ctx, -1, socket_funcs); -+ duk_put_prop_string(ctx, -2, "Socket"); -+ duk_pop(ctx); -+} -diff --git a/dist/source/examples/eventloop/timer-test.js b/dist/source/examples/eventloop/timer-test.js -new file mode 100644 -index 0000000..b5cf116 ---- /dev/null -+++ b/dist/source/examples/eventloop/timer-test.js -@@ -0,0 +1,40 @@ -+/* -+ * Test using timers and intervals. -+ */ -+ -+function main() { -+ var i; -+ var counters = []; -+ var ntimers = 0; -+ -+ print('set interval timer'); -+ var intervalTimer = setInterval(function () { -+ print(new Date().toISOString() + ': timers pending: ' + ntimers); -+ if (ntimers === 0) { -+ clearInterval(intervalTimer); -+ } -+ }, 500); -+ -+ function addTimer(interval) { -+ ntimers++; -+ setTimeout(function () { -+ ntimers--; -+ }, interval); -+ } -+ -+ /* Here the inserts take a lot of time because the underlying timer manager -+ * data structure has O(n) insertion performance. -+ */ -+ print('launch timers'); -+ for (i = 0; i < 4000; i++) { -+ // Math.exp(0)...Math.exp(8) is an uneven distribution between 1...~2980. -+ addTimer(16000 - Math.exp(Math.random() * 8) * 5); -+ } -+ print('timers launched'); -+} -+ -+try { -+ main(); -+} catch (e) { -+ print(e.stack || e); -+} -diff --git a/dist/source/examples/guide/README.rst b/dist/source/examples/guide/README.rst -new file mode 100644 -index 0000000..1933094 ---- /dev/null -+++ b/dist/source/examples/guide/README.rst -@@ -0,0 +1,5 @@ -+=========================== -+Duktape guide example files -+=========================== -+ -+Examples used in the Duktape guide. -diff --git a/dist/source/examples/guide/fib.js b/dist/source/examples/guide/fib.js -new file mode 100644 -index 0000000..2b2982f ---- /dev/null -+++ b/dist/source/examples/guide/fib.js -@@ -0,0 +1,16 @@ -+// fib.js -+function fib(n) { -+ if (n == 0) { return 0; } -+ if (n == 1) { return 1; } -+ return fib(n-1) + fib(n-2); -+} -+ -+function test() { -+ var res = []; -+ for (i = 0; i < 20; i++) { -+ res.push(fib(i)); -+ } -+ print(res.join(' ')); -+} -+ -+test(); -diff --git a/dist/source/examples/guide/prime.js b/dist/source/examples/guide/prime.js -new file mode 100644 -index 0000000..df97d50 ---- /dev/null -+++ b/dist/source/examples/guide/prime.js -@@ -0,0 +1,32 @@ -+// prime.js -+ -+// Pure ECMAScript version of low level helper -+function primeCheckECMAScript(val, limit) { -+ for (var i = 2; i <= limit; i++) { -+ if ((val % i) == 0) { return false; } -+ } -+ return true; -+} -+ -+// Select available helper at load time -+var primeCheckHelper = (this.primeCheckNative || primeCheckECMAScript); -+ -+// Check 'val' for primality -+function primeCheck(val) { -+ if (val == 1 || val == 2) { return true; } -+ var limit = Math.ceil(Math.sqrt(val)); -+ while (limit * limit < val) { limit += 1; } -+ return primeCheckHelper(val, limit); -+} -+ -+// Find primes below one million ending in '9999'. -+function primeTest() { -+ var res = []; -+ -+ print('Have native helper: ' + (primeCheckHelper !== primeCheckECMAScript)); -+ for (var i = 1; i < 1000000; i++) { -+ if (primeCheck(i) && (i % 10000) == 9999) { res.push(i); } -+ } -+ print(res.join(' ')); -+} -+ -diff --git a/dist/source/examples/guide/primecheck.c b/dist/source/examples/guide/primecheck.c -new file mode 100644 -index 0000000..addcc56 ---- /dev/null -+++ b/dist/source/examples/guide/primecheck.c -@@ -0,0 +1,81 @@ -+/* primecheck.c */ -+#include -+#include -+#include -+#include "duktape.h" -+ -+/* For brevity assumes a maximum file length of 16kB. */ -+static void push_file_as_string(duk_context *ctx, const char *filename) { -+ FILE *f; -+ size_t len; -+ char buf[16384]; -+ -+ f = fopen(filename, "rb"); -+ if (f) { -+ len = fread((void *) buf, 1, sizeof(buf), f); -+ fclose(f); -+ duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); -+ } else { -+ duk_push_undefined(ctx); -+ } -+} -+ -+static duk_ret_t native_print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_to_string(ctx, -1)); -+ return 0; -+} -+ -+static duk_ret_t native_prime_check(duk_context *ctx) { -+ int val = duk_require_int(ctx, 0); -+ int lim = duk_require_int(ctx, 1); -+ int i; -+ -+ for (i = 2; i <= lim; i++) { -+ if (val % i == 0) { -+ duk_push_false(ctx); -+ return 1; -+ } -+ } -+ -+ duk_push_true(ctx); -+ return 1; -+} -+ -+int main(int argc, const char *argv[]) { -+ duk_context *ctx = NULL; -+ -+ (void) argc; (void) argv; -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { -+ printf("Failed to create a Duktape heap.\n"); -+ exit(1); -+ } -+ -+ duk_push_global_object(ctx); -+ duk_push_c_function(ctx, native_print, DUK_VARARGS); -+ duk_put_prop_string(ctx, -2, "print"); -+ duk_push_c_function(ctx, native_prime_check, 2 /*nargs*/); -+ duk_put_prop_string(ctx, -2, "primeCheckNative"); -+ -+ push_file_as_string(ctx, "prime.js"); -+ if (duk_peval(ctx) != 0) { -+ printf("Error running: %s\n", duk_safe_to_string(ctx, -1)); -+ goto finished; -+ } -+ duk_pop(ctx); /* ignore result */ -+ -+ duk_get_prop_string(ctx, -1, "primeTest"); -+ if (duk_pcall(ctx, 0) != 0) { -+ printf("Error: %s\n", duk_safe_to_string(ctx, -1)); -+ } -+ duk_pop(ctx); /* ignore result */ -+ -+ finished: -+ duk_destroy_heap(ctx); -+ -+ exit(0); -+} -diff --git a/dist/source/examples/guide/process.js b/dist/source/examples/guide/process.js -new file mode 100644 -index 0000000..62b5011 ---- /dev/null -+++ b/dist/source/examples/guide/process.js -@@ -0,0 +1,12 @@ -+// process.js -+function processLine(line) { -+ return line.trim() -+ .replace(/[<>&"'\u0000-\u001F\u007E-\uFFFF]/g, function(x) { -+ // escape HTML characters -+ return '&#' + x.charCodeAt(0) + ';' -+ }) -+ .replace(/\*(.*?)\*/g, function(x, m) { -+ // automatically bold text between stars -+ return '' + m + ''; -+ }); -+} -diff --git a/dist/source/examples/guide/processlines.c b/dist/source/examples/guide/processlines.c -new file mode 100644 -index 0000000..244e651 ---- /dev/null -+++ b/dist/source/examples/guide/processlines.c -@@ -0,0 +1,78 @@ -+/* processlines.c */ -+#include -+#include -+#include -+#include "duktape.h" -+ -+/* For brevity assumes a maximum file length of 16kB. */ -+static void push_file_as_string(duk_context *ctx, const char *filename) { -+ FILE *f; -+ size_t len; -+ char buf[16384]; -+ -+ f = fopen(filename, "rb"); -+ if (f) { -+ len = fread((void *) buf, 1, sizeof(buf), f); -+ fclose(f); -+ duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); -+ } else { -+ duk_push_undefined(ctx); -+ } -+} -+ -+int main(int argc, const char *argv[]) { -+ duk_context *ctx = NULL; -+ char line[4096]; -+ size_t idx; -+ int ch; -+ -+ (void) argc; (void) argv; -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { -+ printf("Failed to create a Duktape heap.\n"); -+ exit(1); -+ } -+ -+ push_file_as_string(ctx, "process.js"); -+ if (duk_peval(ctx) != 0) { -+ printf("Error: %s\n", duk_safe_to_string(ctx, -1)); -+ goto finished; -+ } -+ duk_pop(ctx); /* ignore result */ -+ -+ memset(line, 0, sizeof(line)); -+ idx = 0; -+ for (;;) { -+ if (idx >= sizeof(line)) { -+ printf("Line too long\n"); -+ exit(1); -+ } -+ -+ ch = fgetc(stdin); -+ if (ch == 0x0a) { -+ line[idx++] = '\0'; -+ -+ duk_push_global_object(ctx); -+ duk_get_prop_string(ctx, -1 /*index*/, "processLine"); -+ duk_push_string(ctx, line); -+ if (duk_pcall(ctx, 1 /*nargs*/) != 0) { -+ printf("Error: %s\n", duk_safe_to_string(ctx, -1)); -+ } else { -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ } -+ duk_pop(ctx); /* pop result/error */ -+ -+ idx = 0; -+ } else if (ch == EOF) { -+ break; -+ } else { -+ line[idx++] = (char) ch; -+ } -+ } -+ -+ finished: -+ duk_destroy_heap(ctx); -+ -+ exit(0); -+} -diff --git a/dist/source/examples/guide/uppercase.c b/dist/source/examples/guide/uppercase.c -new file mode 100644 -index 0000000..03d0869 ---- /dev/null -+++ b/dist/source/examples/guide/uppercase.c -@@ -0,0 +1,42 @@ -+/* uppercase.c */ -+#include -+#include -+#include "duktape.h" -+ -+static int dummy_upper_case(duk_context *ctx) { -+ size_t sz; -+ const char *val = duk_require_lstring(ctx, 0, &sz); -+ size_t i; -+ -+ /* We're going to need 'sz' additional entries on the stack. */ -+ duk_require_stack(ctx, sz); -+ -+ for (i = 0; i < sz; i++) { -+ char ch = val[i]; -+ if (ch >= 'a' && ch <= 'z') { -+ ch = ch - 'a' + 'A'; -+ } -+ duk_push_lstring(ctx, (const char *) &ch, 1); -+ } -+ -+ duk_concat(ctx, sz); -+ return 1; -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ -+ if (argc < 2) { exit(1); } -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { exit(1); } -+ -+ duk_push_c_function(ctx, dummy_upper_case, 1); -+ duk_push_string(ctx, argv[1]); -+ duk_call(ctx, 1); -+ printf("%s -> %s\n", argv[1], duk_to_string(ctx, -1)); -+ duk_pop(ctx); -+ -+ duk_destroy_heap(ctx); -+ return 0; -+} -diff --git a/dist/source/examples/hello/README.rst b/dist/source/examples/hello/README.rst -new file mode 100644 -index 0000000..7afef53 ---- /dev/null -+++ b/dist/source/examples/hello/README.rst -@@ -0,0 +1,5 @@ -+=================== -+Hello world example -+=================== -+ -+Very simple example, most useful for compilation tests. -diff --git a/dist/source/examples/hello/hello.c b/dist/source/examples/hello/hello.c -new file mode 100644 -index 0000000..1c5faff ---- /dev/null -+++ b/dist/source/examples/hello/hello.c -@@ -0,0 +1,46 @@ -+/* -+ * Very simple example program -+ */ -+ -+#include "duktape.h" -+ -+static duk_ret_t native_print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ return 0; -+} -+ -+static duk_ret_t native_adder(duk_context *ctx) { -+ int i; -+ int n = duk_get_top(ctx); /* #args */ -+ double res = 0.0; -+ -+ for (i = 0; i < n; i++) { -+ res += duk_to_number(ctx, i); -+ } -+ -+ duk_push_number(ctx, res); -+ return 1; /* one return value */ -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx = duk_create_heap_default(); -+ -+ (void) argc; (void) argv; /* suppress warning */ -+ -+ duk_push_c_function(ctx, native_print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ duk_push_c_function(ctx, native_adder, DUK_VARARGS); -+ duk_put_global_string(ctx, "adder"); -+ -+ duk_eval_string(ctx, "print('Hello world!');"); -+ -+ duk_eval_string(ctx, "print('2+3=' + adder(2, 3));"); -+ duk_pop(ctx); /* pop eval result */ -+ -+ duk_destroy_heap(ctx); -+ -+ return 0; -+} -diff --git a/dist/source/examples/jxpretty/README.rst b/dist/source/examples/jxpretty/README.rst -new file mode 100644 -index 0000000..5ab43a8 ---- /dev/null -+++ b/dist/source/examples/jxpretty/README.rst -@@ -0,0 +1,5 @@ -+================ -+Jxpretty example -+================ -+ -+Simple command line utility to pretty print JSON in the JX format. -diff --git a/dist/source/examples/jxpretty/jxpretty.c b/dist/source/examples/jxpretty/jxpretty.c -new file mode 100644 -index 0000000..c5134b3 ---- /dev/null -+++ b/dist/source/examples/jxpretty/jxpretty.c -@@ -0,0 +1,76 @@ -+/* -+ * Pretty print JSON from stdin into indented JX. -+ */ -+ -+#include -+#include -+#include "duktape.h" -+ -+static duk_ret_t duk__print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ return 0; -+} -+ -+static duk_ret_t do_jxpretty(duk_context *ctx, void *udata) { -+ FILE *f = stdin; -+ char buf[4096]; -+ size_t ret; -+ -+ (void) udata; -+ -+ for (;;) { -+ if (ferror(f)) { -+ (void) duk_error(ctx, DUK_ERR_ERROR, "ferror() on stdin"); -+ } -+ if (feof(f)) { -+ break; -+ } -+ -+ ret = fread(buf, 1, sizeof(buf), f); -+#if 0 -+ fprintf(stderr, "Read: %ld\n", (long) ret); -+ fflush(stderr); -+#endif -+ if (ret == 0) { -+ break; -+ } -+ -+ duk_require_stack(ctx, 1); -+ duk_push_lstring(ctx, (const char *) buf, ret); -+ } -+ -+ duk_concat(ctx, duk_get_top(ctx)); -+ -+ duk_eval_string(ctx, "(function (v) { print(Duktape.enc('jx', JSON.parse(v), null, 4)); })"); -+ duk_insert(ctx, -2); -+ duk_call(ctx, 1); -+ -+ return 0; -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ duk_int_t rc; -+ -+ /* suppress warnings */ -+ (void) argc; -+ (void) argv; -+ -+ ctx = duk_create_heap_default(); -+ -+ duk_push_c_function(ctx, duk__print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ -+ rc = duk_safe_call(ctx, do_jxpretty, NULL, 0 /*nargs*/, 1 /*nrets*/); -+ if (rc) { -+ fprintf(stderr, "ERROR: %s\n", duk_safe_to_string(ctx, -1)); -+ fflush(stderr); -+ } -+ -+ duk_destroy_heap(ctx); -+ -+ return 0; -+} -diff --git a/dist/source/examples/sandbox/README.rst b/dist/source/examples/sandbox/README.rst -new file mode 100644 -index 0000000..24df0a2 ---- /dev/null -+++ b/dist/source/examples/sandbox/README.rst -@@ -0,0 +1,5 @@ -+=============== -+Sandbox example -+=============== -+ -+Very simple, minimal sandboxing example. -diff --git a/dist/source/examples/sandbox/sandbox.c b/dist/source/examples/sandbox/sandbox.c -new file mode 100644 -index 0000000..c8ad483 ---- /dev/null -+++ b/dist/source/examples/sandbox/sandbox.c -@@ -0,0 +1,266 @@ -+/* -+ * Sandboxing example -+ * -+ * Uses custom memory allocation functions which keep track of total amount -+ * of memory allocated, imposing a maximum total allocation size. -+ */ -+ -+#include -+#include -+#include "duktape.h" -+ -+/* -+ * Memory allocator which backs to standard library memory functions but -+ * keeps a small header to track current allocation size. -+ * -+ * Many other sandbox allocation models are useful, e.g. preallocated pools. -+ */ -+ -+typedef struct { -+ /* The double value in the union is there to ensure alignment is -+ * good for IEEE doubles too. In many 32-bit environments 4 bytes -+ * would be sufficiently aligned and the double value is unnecessary. -+ */ -+ union { -+ size_t sz; -+ double d; -+ } u; -+} alloc_hdr; -+ -+static size_t total_allocated = 0; -+static size_t max_allocated = 256 * 1024; /* 256kB sandbox */ -+ -+static void sandbox_dump_memstate(void) { -+#if 0 -+ fprintf(stderr, "Total allocated: %ld\n", (long) total_allocated); -+ fflush(stderr); -+#endif -+} -+ -+static void *sandbox_alloc(void *udata, duk_size_t size) { -+ alloc_hdr *hdr; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ if (size == 0) { -+ return NULL; -+ } -+ -+ if (total_allocated + size > max_allocated) { -+ fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_alloc\n", -+ (long) size); -+ fflush(stderr); -+ return NULL; -+ } -+ -+ hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr)); -+ if (!hdr) { -+ return NULL; -+ } -+ hdr->u.sz = size; -+ total_allocated += size; -+ sandbox_dump_memstate(); -+ return (void *) (hdr + 1); -+} -+ -+static void *sandbox_realloc(void *udata, void *ptr, duk_size_t size) { -+ alloc_hdr *hdr; -+ size_t old_size; -+ void *t; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ /* Handle the ptr-NULL vs. size-zero cases explicitly to minimize -+ * platform assumptions. You can get away with much less in specific -+ * well-behaving environments. -+ */ -+ -+ if (ptr) { -+ hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr)); -+ old_size = hdr->u.sz; -+ -+ if (size == 0) { -+ total_allocated -= old_size; -+ free((void *) hdr); -+ sandbox_dump_memstate(); -+ return NULL; -+ } else { -+ if (total_allocated - old_size + size > max_allocated) { -+ fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n", -+ (long) size); -+ fflush(stderr); -+ return NULL; -+ } -+ -+ t = realloc((void *) hdr, size + sizeof(alloc_hdr)); -+ if (!t) { -+ return NULL; -+ } -+ hdr = (alloc_hdr *) t; -+ total_allocated -= old_size; -+ total_allocated += size; -+ hdr->u.sz = size; -+ sandbox_dump_memstate(); -+ return (void *) (hdr + 1); -+ } -+ } else { -+ if (size == 0) { -+ return NULL; -+ } else { -+ if (total_allocated + size > max_allocated) { -+ fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n", -+ (long) size); -+ fflush(stderr); -+ return NULL; -+ } -+ -+ hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr)); -+ if (!hdr) { -+ return NULL; -+ } -+ hdr->u.sz = size; -+ total_allocated += size; -+ sandbox_dump_memstate(); -+ return (void *) (hdr + 1); -+ } -+ } -+} -+ -+static void sandbox_free(void *udata, void *ptr) { -+ alloc_hdr *hdr; -+ -+ (void) udata; /* Suppress warning. */ -+ -+ if (!ptr) { -+ return; -+ } -+ hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr)); -+ total_allocated -= hdr->u.sz; -+ free((void *) hdr); -+ sandbox_dump_memstate(); -+} -+ -+/* -+ * Sandbox setup and test -+ */ -+ -+static duk_ret_t duk__print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ return 0; -+} -+ -+static duk_ret_t do_sandbox_test(duk_context *ctx, void *udata) { -+ FILE *f; -+ char buf[4096]; -+ size_t ret; -+ const char *globobj; -+ -+ (void) udata; -+ -+ /* -+ * Setup sandbox -+ */ -+ -+ /* Minimal print() provider. */ -+ duk_push_c_function(ctx, duk__print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ -+ globobj = -+ "({\n" -+ " print: print,\n" -+ " Math: {\n" -+ " max: Math.max\n" -+ " }\n" -+ "})\n"; -+#if 1 -+ fprintf(stderr, "Sandbox global object:\n----------------\n%s----------------\n", globobj); -+ fflush(stderr); -+#endif -+ duk_eval_string(ctx, globobj); -+ duk_set_global_object(ctx); -+ -+ /* -+ * Execute code from specified file -+ */ -+ -+ f = fopen(duk_require_string(ctx, -1), "rb"); -+ if (!f) { -+ duk_error(ctx, DUK_ERR_ERROR, "failed to open file"); -+ } -+ -+ for (;;) { -+ if (ferror(f)) { -+ fclose(f); -+ duk_error(ctx, DUK_ERR_ERROR, "ferror when reading file"); -+ } -+ if (feof(f)) { -+ break; -+ } -+ -+ ret = fread(buf, 1, sizeof(buf), f); -+ if (ret == 0) { -+ break; -+ } -+ -+ duk_push_lstring(ctx, (const char *) buf, ret); -+ } -+ -+ duk_concat(ctx, duk_get_top(ctx) - 1); /* -1 for filename */ -+ -+ /* -> [ ... filename source ] */ -+ -+ duk_insert(ctx, -2); -+ -+ /* -> [ ... source filename ] */ -+ -+ duk_compile(ctx, 0 /*flags*/); /* Compile as program */ -+ duk_call(ctx, 0 /*nargs*/); -+ -+ return 0; -+} -+ -+/* -+ * Main -+ */ -+ -+static void sandbox_fatal(void *udata, const char *msg) { -+ (void) udata; /* Suppress warning. */ -+ fprintf(stderr, "FATAL: %s\n", (msg ? msg : "no message")); -+ fflush(stderr); -+ exit(1); /* must not return */ -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ duk_int_t rc; -+ -+ if (argc < 2) { -+ fprintf(stderr, "Usage: sandbox \n"); -+ fflush(stderr); -+ exit(1); -+ } -+ -+ ctx = duk_create_heap(sandbox_alloc, -+ sandbox_realloc, -+ sandbox_free, -+ NULL, -+ sandbox_fatal); -+ -+ duk_push_string(ctx, argv[1]); -+ rc = duk_safe_call(ctx, do_sandbox_test, NULL, 1 /*nargs*/, 1 /*nrets*/); -+ if (rc) { -+ fprintf(stderr, "ERROR: %s\n", duk_safe_to_string(ctx, -1)); -+ fflush(stderr); -+ } -+ -+ duk_destroy_heap(ctx); -+ -+ /* Should be zero. */ -+ fprintf(stderr, "Final allocation: %ld\n", (long) total_allocated); -+ fflush(stderr); -+ -+ return 1; -+} -diff --git a/dist/source/extras/README.rst b/dist/source/extras/README.rst -new file mode 100644 -index 0000000..1b70160 ---- /dev/null -+++ b/dist/source/extras/README.rst -@@ -0,0 +1,13 @@ -+============== -+Duktape extras -+============== -+ -+Extra modules and utilities. Extras provide functionality that doesn't -+comfortably fit into the main Duktape library, perhaps for footprint or -+portability reasons, but are still useful for most users. -+ -+Extras are maintained and will be bug fixed. However, they don't have the -+same semantic versioning guarantees like the main Duktape library. Extras -+may be dropped without warning as Duktape is versioned. For instance, if -+an extra breaks due to Duktape changes and there is no time to fix it, the -+missing extra won't block a release and will be dropped. -diff --git a/dist/source/extras/alloc-pool/Makefile b/dist/source/extras/alloc-pool/Makefile -new file mode 100644 -index 0000000..6bd6ee5 ---- /dev/null -+++ b/dist/source/extras/alloc-pool/Makefile -@@ -0,0 +1,42 @@ -+# For manual testing; say 'make' in extras/alloc-pool and run ./test. -+ -+CC = gcc -+DEFS = -+#DEFS += '-DDUK_ALLOC_POOL_DEBUG' -+ -+.PHONY: test -+test: -+ rm -rf ./prep -+ echo 'DUK_USE_FATAL_HANDLER:' > opts.yaml -+ echo ' verbatim: "#define DUK_USE_FATAL_HANDLER(udata,msg) my_fatal((msg))"' >> opts.yaml -+ python2 ../../tools/configure.py \ -+ --output-directory ./prep \ -+ --option-file ./opts.yaml \ -+ --fixup-line 'extern void my_fatal(const char *msg);' -+ $(CC) -std=c99 -Wall -Wextra -m32 -Os -otest \ -+ -I./prep ./prep/duktape.c \ -+ $(DEFS) \ -+ duk_alloc_pool.c test.c \ -+ -lm -+ ./test 'print("foo", "bar", 1, 2, 3)' -+ ./test 'alert("foo", "bar", 1, 2, 3)' -+ -+.PHONY: ptrcomptest -+ptrcomptest: -+ rm -rf ./prep -+ echo 'DUK_USE_FATAL_HANDLER:' > opts.yaml -+ echo ' verbatim: "#define DUK_USE_FATAL_HANDLER(udata,msg) my_fatal((msg))"' >> opts.yaml -+ python2 ../../tools/configure.py \ -+ --output-directory ./prep \ -+ --option-file ./opts.yaml \ -+ --fixup-line 'extern void my_fatal(const char *msg);' \ -+ --option-file ../../config/examples/low_memory.yaml \ -+ --option-file ptrcomp.yaml \ -+ --fixup-file ptrcomp_fixup.h -+ $(CC) -std=c99 -Wall -Wextra -m32 -Os -optrcomptest \ -+ -I. -I./prep ./prep/duktape.c \ -+ $(DEFS) \ -+ duk_alloc_pool.c test.c \ -+ -lm -+ ./ptrcomptest 'print("foo", "bar", 1, 2, 3)' -+ ./ptrcomptest 'alert("foo", "bar", 1, 2, 3)' -diff --git a/dist/source/extras/alloc-pool/README.rst b/dist/source/extras/alloc-pool/README.rst -new file mode 100644 -index 0000000..9e579a9 ---- /dev/null -+++ b/dist/source/extras/alloc-pool/README.rst -@@ -0,0 +1,38 @@ -+===================================== -+Pool allocator for low memory targets -+===================================== -+ -+A simple pool allocator which satisfies allocations from preallocated pools -+containing blocks of a certain size. The caller provides a continuous memory -+region and a pool configuration when initializing the allocator. -+ -+The pool configuration specifies the block sizes used, and parameters to -+control how many entries are allocated for each block size. The parameters -+are specified with respect to an arbitrary floating point scaling parameter -+``t`` as follows:: -+ -+ bytes = A*t + B -+ count = floor(bytes / block_size) -+ = floor((A*t + B) / block_size) -+ -+ A: constant which indicates how quickly more bytes are assigned for this -+ block size as the total allocation grows -+ -+ B: constant which indicates the base allocation for this block size, i.e. -+ the allocated needed by Duktape initialization -+ -+Pool initialization finds the largest floating point ``t`` which still fits in -+the memory region provided. Any leftover bytes are sprinkled to the pools to -+minimize wasted space. -+ -+A pool configuration can be written manually (by trial and error) or using -+some automatic tooling such as ``pool_simulator.py``. -+ -+When using pointer compression only a single global pool is supported. This -+reduces code footprint and is usually sufficient in low memory targets. -+ -+Pointer compression functions are defined as inline functions in -+``duk_alloc_pool.h`` to allow the compiler to inline pointer compression when -+appropriate. As a side effect ``duk_config.h`` must include -+``duk_alloc_pool.h`` so that the declarations are visible when compiling -+Duktape. -diff --git a/dist/source/extras/alloc-pool/duk_alloc_pool.c b/dist/source/extras/alloc-pool/duk_alloc_pool.c -new file mode 100644 -index 0000000..240ebf4 ---- /dev/null -+++ b/dist/source/extras/alloc-pool/duk_alloc_pool.c -@@ -0,0 +1,612 @@ -+/* -+ * Pool allocator for low memory targets. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "duktape.h" -+#include "duk_alloc_pool.h" -+ -+/* Define to enable some debug printfs. */ -+/* #define DUK_ALLOC_POOL_DEBUG */ -+ -+/* Define to enable approximate waste tracking. */ -+/* #define DUK_ALLOC_POOL_TRACK_WASTE */ -+ -+/* Define to track global highwater for used and waste bytes. VERY SLOW, only -+ * useful for manual testing. -+ */ -+/* #define DUK_ALLOC_POOL_TRACK_HIGHWATER */ -+ -+#if defined(DUK_ALLOC_POOL_ROMPTR_COMPRESSION) -+#if 0 /* This extern declaration is provided by duktape.h, array provided by duktape.c. */ -+extern const void * const duk_rom_compressed_pointers[]; -+#endif -+const void *duk_alloc_pool_romptr_low = NULL; -+const void *duk_alloc_pool_romptr_high = NULL; -+static void duk__alloc_pool_romptr_init(void); -+#endif -+ -+#if defined(DUK_USE_HEAPPTR16) -+void *duk_alloc_pool_ptrcomp_base = NULL; -+#endif -+ -+#if defined(DUK_ALLOC_POOL_DEBUG) -+static void duk__alloc_pool_dprintf(const char *fmt, ...) { -+ va_list ap; -+ va_start(ap, fmt); -+ vfprintf(stderr, fmt, ap); -+ va_end(ap); -+} -+#endif -+ -+/* -+ * Pool initialization -+ */ -+ -+void *duk_alloc_pool_init(char *buffer, -+ size_t size, -+ const duk_pool_config *configs, -+ duk_pool_state *states, -+ int num_pools, -+ duk_pool_global *global) { -+ double t_min, t_max, t_curr, x; -+ int step, i, j, n; -+ size_t total; -+ char *p; -+ -+ /* XXX: check that 'size' is not too large when using pointer -+ * compression. -+ */ -+ -+ /* To optimize pool counts first come up with a 't' which still allows -+ * total pool size to fit within user provided region. After that -+ * sprinkle any remaining bytes to the counts. Binary search with a -+ * fixed step count; last round uses 't_min' as 't_curr' to ensure it -+ * succeeds. -+ */ -+ -+ t_min = 0.0; /* Unless config is insane, this should always be "good". */ -+ t_max = 1e6; -+ -+ for (step = 0; ; step++) { -+ if (step >= 100) { -+ /* Force "known good", rerun config, and break out. -+ * Deals with rounding corner cases where t_curr is -+ * persistently "bad" even though t_min is a valid -+ * solution. -+ */ -+ t_curr = t_min; -+ } else { -+ t_curr = (t_min + t_max) / 2.0; -+ } -+ -+ for (i = 0, total = 0; i < num_pools; i++) { -+ states[i].size = configs[i].size; -+ -+ /* Target bytes = A*t + B ==> target count = (A*t + B) / block_size. -+ * Rely on A and B being small enough so that 'x' won't wrap. -+ */ -+ x = ((double) configs[i].a * t_curr + (double) configs[i].b) / (double) configs[i].size; -+ -+ states[i].count = (unsigned int) x; -+ total += (size_t) states[i].size * (size_t) states[i].count; -+ if (total > size) { -+ goto bad; -+ } -+ } -+ -+ /* t_curr is good. */ -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_alloc_pool_init: step=%d, t=[%lf %lf %lf] -> total %ld/%ld (good)\n", -+ step, t_min, t_curr, t_max, (long) total, (long) size); -+#endif -+ if (step >= 100) { -+ /* Keep state[] initialization state. The state was -+ * created using the highest 't_min'. -+ */ -+ break; -+ } -+ t_min = t_curr; -+ continue; -+ -+ bad: -+ /* t_curr is bad. */ -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_alloc_pool_init: step=%d, t=[%lf %lf %lf] -> total %ld/%ld (bad)\n", -+ step, t_min, t_curr, t_max, (long) total, (long) size); -+#endif -+ -+ if (step >= 1000) { -+ /* Cannot find any good solution; shouldn't happen -+ * unless config is bad or 'size' is so small that -+ * even a baseline allocation won't fit. -+ */ -+ return NULL; -+ } -+ t_max = t_curr; -+ /* continue */ -+ } -+ -+ /* The base configuration is now good; sprinkle any leftovers to -+ * pools in descending order. Note that for good t_curr, 'total' -+ * indicates allocated bytes so far and 'size - total' indicates -+ * leftovers. -+ */ -+ for (i = num_pools - 1; i >= 0; i--) { -+ while (size - total >= states[i].size) { -+ /* Ignore potential wrapping of states[i].count as the count -+ * is 32 bits and shouldn't wrap in practice. -+ */ -+ states[i].count++; -+ total += states[i].size; -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_alloc_pool_init: sprinkle %ld bytes (%ld left after) to pool index %ld, new count %ld\n", -+ (long) states[i].size, (long) (size - total), (long) i, (long) states[i].count); -+#endif -+ } -+ } -+ -+ /* Pool counts are final. Allocate the user supplied region based -+ * on the final counts, initialize free lists for each block size, -+ * and otherwise finalize 'state' for use. -+ */ -+ p = buffer; -+ global->num_pools = num_pools; -+ global->states = states; -+#if defined(DUK_ALLOC_POOL_TRACK_HIGHWATER) -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_alloc_pool_init: global highwater mark tracking enabled, THIS IS VERY SLOW!\n"); -+#endif -+ global->hwm_used_bytes = 0U; -+ global->hwm_waste_bytes = 0U; -+#endif -+#if defined(DUK_ALLOC_POOL_TRACK_WASTE) -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_alloc_pool_init: approximate waste tracking enabled\n"); -+#endif -+#endif -+ -+#if defined(DUK_USE_HEAPPTR16) -+ /* Register global base value for pointer compression, assumes -+ * a single active pool -4 allows a single subtract to be used and -+ * still ensures no non-NULL pointer encodes to zero. -+ */ -+ duk_alloc_pool_ptrcomp_base = (void *) (p - 4); -+#endif -+ -+ for (i = 0; i < num_pools; i++) { -+ n = (int) states[i].count; -+ if (n > 0) { -+ states[i].first = (duk_pool_free *) p; -+ for (j = 0; j < n; j++) { -+ char *p_next = p + states[i].size; -+ ((duk_pool_free *) p)->next = -+ (j == n - 1) ? (duk_pool_free *) NULL : (duk_pool_free *) p_next; -+ p = p_next; -+ } -+ } else { -+ states[i].first = (duk_pool_free *) NULL; -+ } -+ states[i].alloc_end = p; -+#if defined(DUK_ALLOC_POOL_TRACK_HIGHWATER) -+ states[i].hwm_used_count = 0; -+#endif -+ /* All members of 'state' now initialized. */ -+ -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_alloc_pool_init: block size %5ld, count %5ld, %8ld total bytes, " -+ "end %p\n", -+ (long) states[i].size, (long) states[i].count, -+ (long) states[i].size * (long) states[i].count, -+ (void *) states[i].alloc_end); -+#endif -+ } -+ -+#if defined(DUK_ALLOC_POOL_ROMPTR_COMPRESSION) -+ /* ROM pointer compression precomputation. Assumes a single active -+ * pool. -+ */ -+ duk__alloc_pool_romptr_init(); -+#endif -+ -+ /* Use 'global' as udata. */ -+ return (void *) global; -+} -+ -+/* -+ * Misc helpers -+ */ -+ -+#if defined(DUK_ALLOC_POOL_TRACK_WASTE) -+static void duk__alloc_pool_set_waste_marker(void *ptr, size_t used, size_t size) { -+ /* Rely on the base pointer and size being divisible by 4 and thus -+ * aligned. Use 32-bit markers: a 4-byte resolution is good enough, -+ * and comparing 32 bits at a time makes false waste estimates less -+ * likely than when comparing as bytes. -+ */ -+ duk_uint32_t *p, *p_start, *p_end; -+ size_t used_round; -+ -+ used_round = (used + 3U) & ~0x03U; /* round up to 4 */ -+ p_end = (duk_uint32_t *) ((duk_uint8_t *) ptr + size); -+ p_start = (duk_uint32_t *) ((duk_uint8_t *) ptr + used_round); -+ p = (duk_uint32_t *) p_start; -+ while (p != p_end) { -+ *p++ = DUK_ALLOC_POOL_WASTE_MARKER; -+ } -+} -+#else /* DUK_ALLOC_POOL_TRACK_WASTE */ -+static void duk__alloc_pool_set_waste_marker(void *ptr, size_t used, size_t size) { -+ (void) ptr; (void) used; (void) size; -+} -+#endif /* DUK_ALLOC_POOL_TRACK_WASTE */ -+ -+#if defined(DUK_ALLOC_POOL_TRACK_WASTE) -+static size_t duk__alloc_pool_get_waste_estimate(void *ptr, size_t size) { -+ duk_uint32_t *p, *p_end, *p_start; -+ -+ /* Assumes size is >= 4. */ -+ p_start = (duk_uint32_t *) ptr; -+ p_end = (duk_uint32_t *) ((duk_uint8_t *) ptr + size); -+ p = p_end; -+ -+ /* This scan may cause harmless valgrind complaints: there may be -+ * uninitialized bytes within the legitimate allocation or between -+ * the start of the waste marker and the end of the allocation. -+ */ -+ do { -+ p--; -+ if (*p == DUK_ALLOC_POOL_WASTE_MARKER) { -+ ; -+ } else { -+ return (size_t) (p_end - p - 1) * 4U; -+ } -+ } while (p != p_start); -+ -+ return size; -+} -+#else /* DUK_ALLOC_POOL_TRACK_WASTE */ -+static size_t duk__alloc_pool_get_waste_estimate(void *ptr, size_t size) { -+ (void) ptr; (void) size; -+ return 0; -+} -+#endif /* DUK_ALLOC_POOL_TRACK_WASTE */ -+ -+static int duk__alloc_pool_ptr_in_freelist(duk_pool_state *s, void *ptr) { -+ duk_pool_free *curr; -+ -+ for (curr = s->first; curr != NULL; curr = curr->next) { -+ if ((void *) curr == ptr) { -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+void duk_alloc_pool_get_pool_stats(duk_pool_state *s, duk_pool_stats *res) { -+ void *curr; -+ size_t free_count; -+ size_t used_count; -+ size_t waste_bytes; -+ -+ curr = s->alloc_end - (s->size * s->count); -+ free_count = 0U; -+ waste_bytes = 0U; -+ while (curr != s->alloc_end) { -+ if (duk__alloc_pool_ptr_in_freelist(s, curr)) { -+ free_count++; -+ } else { -+ waste_bytes += duk__alloc_pool_get_waste_estimate(curr, s->size); -+ } -+ curr = curr + s->size; -+ } -+ used_count = (size_t) (s->count - free_count); -+ -+ res->used_count = used_count; -+ res->used_bytes = (size_t) (used_count * s->size); -+ res->free_count = free_count; -+ res->free_bytes = (size_t) (free_count * s->size); -+ res->waste_bytes = waste_bytes; -+#if defined(DUK_ALLOC_POOL_TRACK_HIGHWATER) -+ res->hwm_used_count = s->hwm_used_count; -+#else -+ res->hwm_used_count = 0U; -+#endif -+} -+ -+void duk_alloc_pool_get_global_stats(duk_pool_global *g, duk_pool_global_stats *res) { -+ int i; -+ size_t total_used = 0U; -+ size_t total_free = 0U; -+ size_t total_waste = 0U; -+ -+ for (i = 0; i < g->num_pools; i++) { -+ duk_pool_state *s = &g->states[i]; -+ duk_pool_stats stats; -+ -+ duk_alloc_pool_get_pool_stats(s, &stats); -+ -+ total_used += stats.used_bytes; -+ total_free += stats.free_bytes; -+ total_waste += stats.waste_bytes; -+ } -+ -+ res->used_bytes = total_used; -+ res->free_bytes = total_free; -+ res->waste_bytes = total_waste; -+#if defined(DUK_ALLOC_POOL_TRACK_HIGHWATER) -+ res->hwm_used_bytes = g->hwm_used_bytes; -+ res->hwm_waste_bytes = g->hwm_waste_bytes; -+#else -+ res->hwm_used_bytes = 0U; -+ res->hwm_waste_bytes = 0U; -+#endif -+} -+ -+#if defined(DUK_ALLOC_POOL_TRACK_HIGHWATER) -+static void duk__alloc_pool_update_highwater(duk_pool_global *g) { -+ int i; -+ size_t total_used = 0U; -+ size_t total_free = 0U; -+ size_t total_waste = 0U; -+ -+ /* Per pool highwater used count, useful to checking if a pool is -+ * too small. -+ */ -+ for (i = 0; i < g->num_pools; i++) { -+ duk_pool_state *s = &g->states[i]; -+ duk_pool_stats stats; -+ -+ duk_alloc_pool_get_pool_stats(s, &stats); -+ if (stats.used_count > s->hwm_used_count) { -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk__alloc_pool_update_highwater: pool %ld (%ld bytes) highwater updated: count %ld -> %ld\n", -+ (long) i, (long) s->size, -+ (long) s->hwm_used_count, (long) stats.used_count); -+#endif -+ s->hwm_used_count = stats.used_count; -+ } -+ -+ total_used += stats.used_bytes; -+ total_free += stats.free_bytes; -+ total_waste += stats.waste_bytes; -+ } -+ -+ /* Global highwater mark for used and waste bytes. Both fields are -+ * updated from the same snapshot based on highest used count. -+ * This is VERY, VERY slow and only useful for development. -+ * (Note that updating HWM states for pools individually and then -+ * summing them won't create a consistent global snapshot. There -+ * are still easy ways to make this much, much faster.) -+ */ -+ if (total_used > g->hwm_used_bytes) { -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk__alloc_pool_update_highwater: global highwater updated: used=%ld, bytes=%ld -> " -+ "used=%ld, bytes=%ld\n", -+ (long) g->hwm_used_bytes, (long) g->hwm_waste_bytes, -+ (long) total_used, (long) total_waste); -+#endif -+ g->hwm_used_bytes = total_used; -+ g->hwm_waste_bytes = total_waste; -+ } -+} -+#else /* DUK_ALLOC_POOL_TRACK_HIGHWATER */ -+static void duk__alloc_pool_update_highwater(duk_pool_global *g) { -+ (void) g; -+} -+#endif /* DUK_ALLOC_POOL_TRACK_HIGHWATER */ -+ -+/* -+ * Allocation providers -+ */ -+ -+void *duk_alloc_pool(void *udata, duk_size_t size) { -+ duk_pool_global *g = (duk_pool_global *) udata; -+ int i, n; -+ -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_alloc_pool: %p %ld\n", udata, (long) size); -+#endif -+ -+ if (size == 0) { -+ return NULL; -+ } -+ -+ for (i = 0, n = g->num_pools; i < n; i++) { -+ duk_pool_state *st = g->states + i; -+ -+ if (size <= st->size) { -+ duk_pool_free *res = st->first; -+ if (res != NULL) { -+ st->first = res->next; -+ duk__alloc_pool_set_waste_marker((void *) res, size, st->size); -+ duk__alloc_pool_update_highwater(g); -+ return (void *) res; -+ } -+ } -+ -+ /* Allocation doesn't fit or no free entries, try to borrow -+ * from the next block size. There's no support for preventing -+ * a borrow at present. -+ */ -+ } -+ -+ return NULL; -+} -+ -+void *duk_realloc_pool(void *udata, void *ptr, duk_size_t size) { -+ duk_pool_global *g = (duk_pool_global *) udata; -+ int i, j, n; -+ -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_realloc_pool: %p %p %ld\n", udata, ptr, (long) size); -+#endif -+ -+ if (ptr == NULL) { -+ return duk_alloc_pool(udata, size); -+ } -+ if (size == 0) { -+ duk_free_pool(udata, ptr); -+ return NULL; -+ } -+ -+ /* Non-NULL pointers are necessarily from the pool so we should -+ * always be able to find the allocation. -+ */ -+ -+ for (i = 0, n = g->num_pools; i < n; i++) { -+ duk_pool_state *st = g->states + i; -+ char *new_ptr; -+ -+ /* Because 'ptr' is assumed to be in the pool and pools are -+ * allocated in sequence, it suffices to check for end pointer -+ * only. -+ */ -+ if ((char *) ptr >= st->alloc_end) { -+ continue; -+ } -+ -+ if (size <= st->size) { -+ /* Allocation still fits existing allocation. Check if -+ * we can shrink the allocation to a smaller block size -+ * (smallest possible). -+ */ -+ for (j = 0; j < i; j++) { -+ duk_pool_state *st2 = g->states + j; -+ -+ if (size <= st2->size) { -+ new_ptr = (char *) st2->first; -+ if (new_ptr != NULL) { -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_realloc_pool: shrink, block size %ld -> %ld\n", -+ (long) st->size, (long) st2->size); -+#endif -+ st2->first = ((duk_pool_free *) new_ptr)->next; -+ memcpy((void *) new_ptr, (const void *) ptr, (size_t) size); -+ ((duk_pool_free *) ptr)->next = st->first; -+ st->first = (duk_pool_free *) ptr; -+ duk__alloc_pool_set_waste_marker((void *) new_ptr, size, st2->size); -+ duk__alloc_pool_update_highwater(g); -+ return (void *) new_ptr; -+ } -+ } -+ } -+ -+ /* Failed to shrink; return existing pointer. */ -+ duk__alloc_pool_set_waste_marker((void *) ptr, size, st->size); -+ return ptr; -+ } -+ -+ /* Find first free larger block. */ -+ for (j = i + 1; j < n; j++) { -+ duk_pool_state *st2 = g->states + j; -+ -+ if (size <= st2->size) { -+ new_ptr = (char *) st2->first; -+ if (new_ptr != NULL) { -+ st2->first = ((duk_pool_free *) new_ptr)->next; -+ memcpy((void *) new_ptr, (const void *) ptr, (size_t) st->size); -+ ((duk_pool_free *) ptr)->next = st->first; -+ st->first = (duk_pool_free *) ptr; -+ duk__alloc_pool_set_waste_marker((void *) new_ptr, size, st2->size); -+ duk__alloc_pool_update_highwater(g); -+ return (void *) new_ptr; -+ } -+ } -+ } -+ -+ /* Failed to resize. */ -+ return NULL; -+ } -+ -+ /* We should never be here because 'ptr' should be a valid pool -+ * entry and thus always found above. -+ */ -+ return NULL; -+} -+ -+void duk_free_pool(void *udata, void *ptr) { -+ duk_pool_global *g = (duk_pool_global *) udata; -+ int i, n; -+ -+#if defined(DUK_ALLOC_POOL_DEBUG) -+ duk__alloc_pool_dprintf("duk_free_pool: %p %p\n", udata, ptr); -+#endif -+ -+ if (ptr == NULL) { -+ return; -+ } -+ -+ for (i = 0, n = g->num_pools; i < n; i++) { -+ duk_pool_state *st = g->states + i; -+ -+ /* Enough to check end address only. */ -+ if ((char *) ptr >= st->alloc_end) { -+ continue; -+ } -+ -+ ((duk_pool_free *) ptr)->next = st->first; -+ st->first = (duk_pool_free *) ptr; -+#if 0 /* never necessary when freeing */ -+ duk__alloc_pool_update_highwater(g); -+#endif -+ return; -+ } -+ -+ /* We should never be here because 'ptr' should be a valid pool -+ * entry and thus always found above. -+ */ -+} -+ -+/* -+ * Pointer compression -+ */ -+ -+#if defined(DUK_ALLOC_POOL_ROMPTR_COMPRESSION) -+static void duk__alloc_pool_romptr_init(void) { -+ /* Scan ROM pointer range for faster detection of "is 'p' a ROM pointer" -+ * later on. -+ */ -+ const void * const * ptrs = (const void * const *) duk_rom_compressed_pointers; -+ duk_alloc_pool_romptr_low = duk_alloc_pool_romptr_high = (const void *) *ptrs; -+ while (*ptrs) { -+ if (*ptrs > duk_alloc_pool_romptr_high) { -+ duk_alloc_pool_romptr_high = (const void *) *ptrs; -+ } -+ if (*ptrs < duk_alloc_pool_romptr_low) { -+ duk_alloc_pool_romptr_low = (const void *) *ptrs; -+ } -+ ptrs++; -+ } -+} -+#endif -+ -+/* Encode/decode functions are defined in the header to allow inlining. */ -+ -+#if defined(DUK_ALLOC_POOL_ROMPTR_COMPRESSION) -+duk_uint16_t duk_alloc_pool_enc16_rom(void *ptr) { -+ /* The if-condition should be the fastest possible check -+ * for "is 'ptr' in ROM?". If pointer is in ROM, we'd like -+ * to compress it quickly. Here we just scan a ~1K array -+ * which is very bad for performance. -+ */ -+ const void * const * ptrs = duk_rom_compressed_pointers; -+ while (*ptrs) { -+ if (*ptrs == ptr) { -+ return DUK_ALLOC_POOL_ROMPTR_FIRST + (duk_uint16_t) (ptrs - duk_rom_compressed_pointers); -+ } -+ ptrs++; -+ } -+ -+ /* We should really never be here: Duktape should only be -+ * compressing pointers which are in the ROM compressed -+ * pointers list, which are known when configuring sources. -+ * We go on, causing a pointer compression error. -+ */ -+ return 0; -+} -+#endif -diff --git a/dist/source/extras/alloc-pool/duk_alloc_pool.h b/dist/source/extras/alloc-pool/duk_alloc_pool.h -new file mode 100644 -index 0000000..671f761 ---- /dev/null -+++ b/dist/source/extras/alloc-pool/duk_alloc_pool.h -@@ -0,0 +1,231 @@ -+#if !defined(DUK_ALLOC_POOL_H_INCLUDED) -+#define DUK_ALLOC_POOL_H_INCLUDED -+ -+#include "duktape.h" -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+/* 32-bit (big endian) marker used at the end of pool entries so that wasted -+ * space can be detected. Waste tracking must be enabled explicitly. -+ */ -+#if defined(DUK_ALLOC_POOL_TRACK_WASTE) -+#define DUK_ALLOC_POOL_WASTE_MARKER 0xedcb2345UL -+#endif -+ -+/* Pointer compression with ROM strings/objects: -+ * -+ * For now, use DUK_USE_ROM_OBJECTS to signal the need for compressed ROM -+ * pointers. DUK_USE_ROM_PTRCOMP_FIRST is provided for the ROM pointer -+ * compression range minimum to avoid duplication in user code. -+ */ -+#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) -+#define DUK_ALLOC_POOL_ROMPTR_COMPRESSION -+#define DUK_ALLOC_POOL_ROMPTR_FIRST DUK_USE_ROM_PTRCOMP_FIRST -+ -+/* This extern declaration is provided by duktape.h, array provided by duktape.c. -+ * Because duk_config.h may include this file (to get the inline functions) we -+ * need to forward declare this also here. -+ */ -+extern const void * const duk_rom_compressed_pointers[]; -+#endif -+ -+/* Pool configuration for a certain block size. */ -+typedef struct { -+ unsigned int size; /* must be divisible by 4 and >= sizeof(void *) */ -+ unsigned int a; /* bytes (not count) to allocate: a*t + b, t is an arbitrary scale parameter */ -+ unsigned int b; -+} duk_pool_config; -+ -+/* Freelist entry, must fit into the smallest block size. */ -+struct duk_pool_free; -+typedef struct duk_pool_free duk_pool_free; -+struct duk_pool_free { -+ duk_pool_free *next; -+}; -+ -+/* Pool state for a certain block size. */ -+typedef struct { -+ duk_pool_free *first; -+ char *alloc_end; -+ unsigned int size; -+ unsigned int count; -+#if defined(DUK_ALLOC_POOL_TRACK_HIGHWATER) -+ unsigned int hwm_used_count; -+#endif -+} duk_pool_state; -+ -+/* Statistics for a certain pool. */ -+typedef struct { -+ size_t used_count; -+ size_t used_bytes; -+ size_t free_count; -+ size_t free_bytes; -+ size_t waste_bytes; -+ size_t hwm_used_count; -+} duk_pool_stats; -+ -+/* Top level state for all pools. Pointer to this struct is used as the allocator -+ * userdata pointer. -+ */ -+typedef struct { -+ int num_pools; -+ duk_pool_state *states; -+#if defined(DUK_ALLOC_POOL_TRACK_HIGHWATER) -+ size_t hwm_used_bytes; -+ size_t hwm_waste_bytes; -+#endif -+} duk_pool_global; -+ -+/* Statistics for the entire set of pools. */ -+typedef struct { -+ size_t used_bytes; -+ size_t free_bytes; -+ size_t waste_bytes; -+ size_t hwm_used_bytes; -+ size_t hwm_waste_bytes; -+} duk_pool_global_stats; -+ -+/* Initialize a pool allocator, arguments: -+ * - buffer and size: continuous region to use for pool, must align to 4 -+ * - config: configuration for pools in ascending block size -+ * - state: state for pools, matches config order -+ * - num_pools: number of entries in 'config' and 'state' -+ * - global: global state structure -+ * -+ * The 'config', 'state', and 'global' pointers must be valid beyond the init -+ * call, as long as the pool is used. -+ * -+ * Returns a void pointer to be used as userdata for the allocator functions. -+ * Concretely the return value will be "(void *) global", i.e. the global -+ * state struct. If pool init fails, the return value will be NULL. -+ */ -+void *duk_alloc_pool_init(char *buffer, -+ size_t size, -+ const duk_pool_config *configs, -+ duk_pool_state *states, -+ int num_pools, -+ duk_pool_global *global); -+ -+/* Duktape allocation providers. Typing matches Duktape requirements. */ -+void *duk_alloc_pool(void *udata, duk_size_t size); -+void *duk_realloc_pool(void *udata, void *ptr, duk_size_t size); -+void duk_free_pool(void *udata, void *ptr); -+ -+/* Stats. */ -+void duk_alloc_pool_get_pool_stats(duk_pool_state *s, duk_pool_stats *res); -+void duk_alloc_pool_get_global_stats(duk_pool_global *g, duk_pool_global_stats *res); -+ -+/* Duktape pointer compression global state (assumes single pool). */ -+#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) -+extern const void *duk_alloc_pool_romptr_low; -+extern const void *duk_alloc_pool_romptr_high; -+duk_uint16_t duk_alloc_pool_enc16_rom(void *ptr); -+#endif -+#if defined(DUK_USE_HEAPPTR16) -+extern void *duk_alloc_pool_ptrcomp_base; -+#endif -+ -+#if 0 -+duk_uint16_t duk_alloc_pool_enc16(void *ptr); -+void *duk_alloc_pool_dec16(duk_uint16_t val); -+#endif -+ -+/* Inlined pointer compression functions. Gcc and clang -Os won't in -+ * practice inline these without an "always inline" attribute because it's -+ * more size efficient (by a few kB) to use explicit calls instead. Having -+ * these defined inline here allows performance optimized builds to inline -+ * pointer compression operations. -+ * -+ * Pointer compression assumes there's a single globally registered memory -+ * pool which makes pointer compression more efficient. This would be easy -+ * to fix by adding a userdata pointer to the compression functions and -+ * plumbing the heap userdata from the compression/decompression macros. -+ */ -+ -+/* DUK_ALWAYS_INLINE is not a public API symbol so it may go away in even a -+ * minor update. But it's pragmatic for this extra because it handles many -+ * compilers via duk_config.h detection. Check that the macro exists so that -+ * if it's gone, we can still compile. -+ */ -+#if defined(DUK_ALWAYS_INLINE) -+#define DUK__ALLOC_POOL_ALWAYS_INLINE DUK_ALWAYS_INLINE -+#else -+#define DUK__ALLOC_POOL_ALWAYS_INLINE /* nop */ -+#endif -+ -+#if defined(DUK_USE_HEAPPTR16) -+static DUK__ALLOC_POOL_ALWAYS_INLINE duk_uint16_t duk_alloc_pool_enc16(void *ptr) { -+ if (ptr == NULL) { -+ /* With 'return 0' gcc and clang -Os generate inefficient code. -+ * For example, gcc -Os generates: -+ * -+ * 0804911d : -+ * 804911d: 55 push %ebp -+ * 804911e: 85 c0 test %eax,%eax -+ * 8049120: 89 e5 mov %esp,%ebp -+ * 8049122: 74 0b je 804912f -+ * 8049124: 2b 05 e4 90 07 08 sub 0x80790e4,%eax -+ * 804912a: c1 e8 02 shr $0x2,%eax -+ * 804912d: eb 02 jmp 8049131 -+ * 804912f: 31 c0 xor %eax,%eax -+ * 8049131: 5d pop %ebp -+ * 8049132: c3 ret -+ * -+ * The NULL path checks %eax for zero; if it is zero, a zero -+ * is unnecessarily loaded into %eax again. The non-zero path -+ * has an unnecessary jump as a side effect of this. -+ * -+ * Using 'return (duk_uint16_t) (intptr_t) ptr;' generates similarly -+ * inefficient code; not sure how to make the result better. -+ */ -+ return 0; -+ } -+#if defined(DUK_ALLOC_POOL_ROMPTR_COMPRESSION) -+ if (ptr >= duk_alloc_pool_romptr_low && ptr <= duk_alloc_pool_romptr_high) { -+ /* This is complex enough now to need a separate function. */ -+ return duk_alloc_pool_enc16_rom(ptr); -+ } -+#endif -+ return (duk_uint16_t) (((size_t) ((char *) ptr - (char *) duk_alloc_pool_ptrcomp_base)) >> 2); -+} -+ -+static DUK__ALLOC_POOL_ALWAYS_INLINE void *duk_alloc_pool_dec16(duk_uint16_t val) { -+ if (val == 0) { -+ /* As with enc16 the gcc and clang -Os output is inefficient, -+ * e.g. gcc -Os: -+ * -+ * 08049133 : -+ * 8049133: 55 push %ebp -+ * 8049134: 66 85 c0 test %ax,%ax -+ * 8049137: 89 e5 mov %esp,%ebp -+ * 8049139: 74 0e je 8049149 -+ * 804913b: 8b 15 e4 90 07 08 mov 0x80790e4,%edx -+ * 8049141: 0f b7 c0 movzwl %ax,%eax -+ * 8049144: 8d 04 82 lea (%edx,%eax,4),%eax -+ * 8049147: eb 02 jmp 804914b -+ * 8049149: 31 c0 xor %eax,%eax -+ * 804914b: 5d pop %ebp -+ * 804914c: c3 ret -+ */ -+ return NULL; -+ } -+#if defined(DUK_ALLOC_POOL_ROMPTR_COMPRESSION) -+ if (val >= DUK_ALLOC_POOL_ROMPTR_FIRST) { -+ /* This is a blind lookup, could check index validity. -+ * Duktape should never decompress a pointer which would -+ * be out-of-bounds here. -+ */ -+ return (void *) (intptr_t) (duk_rom_compressed_pointers[val - DUK_ALLOC_POOL_ROMPTR_FIRST]); -+ } -+#endif -+ return (void *) ((char *) duk_alloc_pool_ptrcomp_base + (((size_t) val) << 2)); -+} -+#endif -+ -+#if defined(__cplusplus) -+} -+#endif /* end 'extern "C"' wrapper */ -+ -+#endif /* DUK_ALLOC_POOL_H_INCLUDED */ -diff --git a/dist/source/extras/alloc-pool/ptrcomp.yaml b/dist/source/extras/alloc-pool/ptrcomp.yaml -new file mode 100644 -index 0000000..9ce58f4 ---- /dev/null -+++ b/dist/source/extras/alloc-pool/ptrcomp.yaml -@@ -0,0 +1,16 @@ -+DUK_USE_REFCOUNT16: true -+DUK_USE_STRHASH16: true -+DUK_USE_STRLEN16: true -+DUK_USE_BUFLEN16: true -+DUK_USE_OBJSIZES16: true -+DUK_USE_HSTRING_CLEN: false -+DUK_USE_HOBJECT_HASH_PART: false -+DUK_USE_HEAPPTR16: true -+DUK_USE_HEAPPTR_ENC16: -+ verbatim: "#define DUK_USE_HEAPPTR_ENC16(ud,p) duk_alloc_pool_enc16((p))" -+DUK_USE_HEAPPTR_DEC16: -+ verbatim: "#define DUK_USE_HEAPPTR_DEC16(ud,p) duk_alloc_pool_dec16((p))" -+ -+#DUK_USE_ROM_OBJECTS: true -+#DUK_USE_ROM_STRINGS: true -+#DUK_USE_ROM_GLOBAL_INHERIT: true -diff --git a/dist/source/extras/alloc-pool/ptrcomp_fixup.h b/dist/source/extras/alloc-pool/ptrcomp_fixup.h -new file mode 100644 -index 0000000..fec0ff5 ---- /dev/null -+++ b/dist/source/extras/alloc-pool/ptrcomp_fixup.h -@@ -0,0 +1,2 @@ -+/* To provide declarations for inline pointer compression functions. */ -+#include "duk_alloc_pool.h" -diff --git a/dist/source/extras/alloc-pool/test.c b/dist/source/extras/alloc-pool/test.c -new file mode 100644 -index 0000000..f272244 ---- /dev/null -+++ b/dist/source/extras/alloc-pool/test.c -@@ -0,0 +1,114 @@ -+#include -+#include -+#include "duktape.h" -+#include "duk_alloc_pool.h" -+ -+void my_fatal(const char *msg) { -+ fprintf(stderr, "*** FATAL: %s\n", msg ? msg : "no message"); -+ fflush(stderr); -+ abort(); -+} -+ -+static duk_ret_t my_print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_safe_to_string(ctx, -1)); -+ return 1; -+} -+ -+static void dump_pool_state(duk_pool_global *g) { -+ int i; -+ long total_size = 0; -+ long total_used = 0; -+ -+ for (i = 0; i < g->num_pools; i++) { -+ duk_pool_state *st = g->states + i; -+ int free, used; -+ duk_pool_free *f; -+ -+ for (free = 0, f = st->first; f; f = f->next) { -+ free++; -+ } -+ used = st->count - free; -+ printf("Pool %2d: block size %5d, count %4d/%4d, bytes %6d/%6d\n", -+ i, (int) st->size, used, (int) st->count, -+ (int) st->size * used, (int) st->size * (int) st->count); -+ -+ total_size += (long) st->size * (long) st->count; -+ total_used += (long) st->size * (long) used; -+ } -+ printf("=== Total: %ld/%ld, free %ld\n", -+ (long) total_used, (long) total_size, (long) (total_size - total_used)); -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ int i; -+ int exitcode = 0; -+ -+ /* NOTE! This pool configuration is NOT a good pool configuration -+ * for practical use (and is not intended to be one). A production -+ * pool configuration should be created using measurements. -+ */ -+ const duk_pool_config pool_configs[15] = { -+ { 16, 20, 200 }, -+ { 20, 40, 100 }, -+ { 24, 40, 100 }, -+ { 32, 60, 50 }, -+ { 40, 60, 50 }, -+ { 48, 60, 50 }, -+ { 56, 60, 50 }, -+ { 64, 60, 50 }, -+ { 80, 60, 50 }, -+ { 256, 100, 10 }, -+ { 1024, 20, 2 }, -+ { 2048, 20, 2 }, -+ { 4096, 100, 2 }, -+ { 6144, 60, 2 }, -+ { 8192, 100, 2 }, -+ }; -+ duk_pool_state pool_states[15]; /* Count must match pool_configs[]. */ -+ duk_pool_global pool_global; -+ -+ char buffer[200000]; -+ void *pool_udata; -+ -+ pool_udata = duk_alloc_pool_init(buffer, sizeof(buffer), pool_configs, pool_states, sizeof(pool_configs) / sizeof(duk_pool_config), &pool_global); -+ if (!pool_udata) { -+ return 1; -+ } -+ -+ printf("Pool after pool init:\n"); -+ dump_pool_state(&pool_global); -+ -+ ctx = duk_create_heap(duk_alloc_pool, duk_realloc_pool, duk_free_pool, pool_udata, NULL); -+ if (!ctx) { -+ return 1; -+ } -+ -+ printf("Pool after Duktape heap creation:\n"); -+ dump_pool_state(&pool_global); -+ -+ duk_push_c_function(ctx, my_print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ duk_push_c_function(ctx, my_print, DUK_VARARGS); -+ duk_put_global_string(ctx, "alert"); -+ printf("top after init: %ld\n", (long) duk_get_top(ctx)); -+ -+ for (i = 1; i < argc; i++) { -+ printf("Evaling: %s\n", argv[i]); -+ if (duk_peval_string(ctx, argv[i]) != 0) { -+ exitcode = 1; -+ } -+ printf("--> %s\n", duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ } -+ -+ printf("Pool after evaling code:\n"); -+ dump_pool_state(&pool_global); -+ -+ printf("Done\n"); -+ duk_destroy_heap(ctx); -+ return exitcode; -+} -diff --git a/dist/source/extras/cbor/Makefile b/dist/source/extras/cbor/Makefile -new file mode 100644 -index 0000000..1e8a6d4 ---- /dev/null -+++ b/dist/source/extras/cbor/Makefile -@@ -0,0 +1,261 @@ -+# For manual testing; say 'make' in extras/cbor. -+ -+VALGRIND = valgrind -+CC = gcc -+CCOPTS = -std=c99 -Wall -Wextra -O2 -+#CCOPTS += -fsanitize=undefined -+ -+.PHONY: all -+all: clean jsoncbor test-runs -+ -+.PHONY: clean -+clean: -+ -rm -rf ./prep -+ -rm -f jsoncbor -+ -rm -f appendix_a.json -+ -+jsoncbor: jsoncbor.c duk_cbor.c duk_cbor.h -+ -rm -rf ./prep -+ python2 ../../tools/configure.py --quiet --output-directory ./prep \ -+ -DDUK_USE_JSON_DECNUMBER_FASTPATH \ -+ -DDUK_USE_JSON_DECSTRING_FASTPATH \ -+ -DDUK_USE_JSON_EATWHITE_FASTPATH \ -+ -DDUK_USE_JSON_QUOTESTRING_FASTPATH \ -+ -DDUK_USE_JSON_STRINGIFY_FASTPATH -+ $(CC) $(CCOPTS) -o $@ -I./prep -I. ./prep/duktape.c duk_cbor.c jsoncbor.c -lm -+ -+appendix_a.json: -+ wget -O $@ https://raw.githubusercontent.com/cbor/test-vectors/master/appendix_a.json -+ -+.PHONY: test-runs -+test-runs: jsoncbor \ -+ enc-primitives enc-number enc-buffer enc-string enc-array enc-object enc-half-float enc-float enc-misc \ -+ dec-half-float dec-half-float dec-array dec-object -+ -+.PHONY: test-vectors -+test-vectors: appendix_a.json -+ echo "Expects 'duk' to exist in local directory for now..." -+ ./duk run_testvectors.js -+ -+.PHONY: dec-half-float -+dec-half-float: jsoncbor -+ @echo "half-float zero" -+ python -c 'import sys; sys.stdout.write("\xf9\x00\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x00\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x80\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x80\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ @echo "half-float denormal" -+ python -c 'import sys; sys.stdout.write("\xf9\x00\x01")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x00\x01")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x80\x01")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x80\x01")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x00\x02")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x00\x02")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x80\x02")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x80\x02")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x03\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x03\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x83\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x83\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ @echo "half-float normal" -+ python -c 'import sys; sys.stdout.write("\xf9\x04\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x04\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x84\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x84\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x07\xfe")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x07\xfe")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x87\xfe")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x87\xfe")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x08\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x08\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x88\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x88\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x78\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x78\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\xf8\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\xf8\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x7b\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x7b\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\xfb\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\xfb\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ @echo "half-float inf" -+ python -c 'import sys; sys.stdout.write("\xf9\x7c\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x7c\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\xfc\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\xfc\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ @echo "half-float nan" -+ python -c 'import sys; sys.stdout.write("\xf9\x7c\x01")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x7c\x01")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\xfc\x01")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\xfc\x01")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x7e\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x7e\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\xfe\x00")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\xfe\x00")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\x7f\x12")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\x7f\x12")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xf9\xff\x12")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xf9\xff\x12")'| $(VALGRIND) -q ./jsoncbor -d -+ -+.PHONY: dec-array -+dec-array: jsoncbor -+ python -c 'import sys; sys.stdout.write("\x9f\x01\x02\x03\x9f\xff\x04\x80\x80\x9f\x10\x11\xff\x84\x04\x03\x02\x01\xff")' | python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x9f\x01\x02\x03\x9f\xff\x04\x80\x80\x9f\x10\x11\xff\x84\x04\x03\x02\x01\xff")' | $(VALGRIND) -q ./jsoncbor -d -+ -+.PHONY: dec-object -+dec-object: jsoncbor -+ python -c 'import sys; sys.stdout.write("\xbf\x63foo\x63bar\x63bar\xa0\x64quux\xbf\xff\x63baz\xa2\x61a\x61b\x61c\x61d\x65quuux\xbf\x61x\x61y\x61z\x61w\xff\xff")' | python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xbf\x63foo\x63bar\x63bar\xa0\x64quux\xbf\xff\x63baz\xa2\x61a\x61b\x61c\x61d\x65quuux\xbf\x61x\x61y\x61z\x61w\xff\xff")' | $(VALGRIND) -q ./jsoncbor -d -+ -+.PHONY: dec-misc -+dec-misc: jsoncbor -+ python -c 'import sys; sys.stdout.write("\xa1cfoocbar")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xa1cfoocbar")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xa1\xa0\xa0")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xa1\xa0\xa0")'| $(VALGRIND) -q ./jsoncbor -d # object key, gets string coerced in JSON output -+ python -c 'import sys; sys.stdout.write("\x7f\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x7f\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\x7f`````````````````````````````````````````````````````````````````````````````````````````````````````````\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x7f`````````````````````````````````````````````````````````````````````````````````````````````````````````\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\x7fcfoo\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x7fcfoo\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\x7fcfoocbaraqau`auax\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x7fcfoocbaraqau`auax\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\x5f\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x5f\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\x5f@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x5f@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\x5fCfoo\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x5fCfoo\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\x5fCfooCbarAqAu@AuAx\xff")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\x5fCfooCbarAqAu@AuAx\xff")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xc0cfoo")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xc0cfoo")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xc0\xc1cfoo")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xc0\xc1cfoo")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xc0\xd7cfoo")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xc0\xd7cfoo")'| $(VALGRIND) -q ./jsoncbor -d -+ python -c 'import sys; sys.stdout.write("\xc0\xd8\xffcfoo")'| python cbordecode.py -+ python -c 'import sys; sys.stdout.write("\xc0\xd8\xffcfoo")'| $(VALGRIND) -q ./jsoncbor -d -+ -+ -+.PHONY: enc-primitives -+enc-primitives: jsoncbor -+ echo 'void 0' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo 'null' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo 'true' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo 'false' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ -+.PHONY: enc-number -+enc-number: jsoncbor -+ echo '0' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '0.1' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '1' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '23' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '24' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '25' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '255' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '256' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '65535' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '65536' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '65536.9' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '1048576' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '4294967295' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '4294967296' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py # shortest encoding: ieee single -+ echo '4294967297' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '0xdeadbeef' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '3.141592653589793' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-0' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-0.1' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-1' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-23' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-24' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-25' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-255' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-256' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-257' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-65535' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-65536' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-65536.9' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-65537' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-1048576' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-4294967295' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-4294967296' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-4294967297' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-0xdeadbeef' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-3.141592653589793' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '1/0' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py # shortest encoding: half-float -+ echo '0/0' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py # shortest encoding: half-float -+ echo '-1/0' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py # shortest encoding: half-float -+ -+.PHONY: enc-half-float -+enc-half-float: -+ echo '1.5' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '1/16384' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '1/32768' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-1.5' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-1/16384' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-1/32768' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ -+.PHONY: enc-float -+enc-float: -+ echo '0xffffffff' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '0x100000000' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '0x1fedcbe0000000000' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '0x1fedcbf0000000000' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ # Unlike for positive integers, 0x100000000 encodes to a cbor integer (sint). -+ # Then -0x100000001 doesn't encode to a float because the mantissa is too long. -+ echo '-0x100000000' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-0x100000001' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-0x100010000' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-0x1fedcbe0000000000' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '-0x1fedcbf0000000000' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ -+.PHONY: enc-buffer -+enc-buffer: jsoncbor -+ echo '(function () { var p = Uint8Array.allocPlain(0); return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(1); p[0] = 0xfe; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(2); p[0] = 0xc0; p[1] = 0x80; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(3); p[0] = 0x31; p[1] = 0x4a; p[2] = 0x7a; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(23); p[22] = 0xfe; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(24); p[23] = 0xfe; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(255); p[254] = 0xfe; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(256); p[255] = 0xfe; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = Uint8Array.allocPlain(256); p[255] = 0xfe; return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '(function () { var p = new Uint16Array([ 1, 2, 3, 4 ]); return p; })()' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ -+.PHONY: enc-string -+enc-string: jsoncbor -+ echo '""' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '"foo"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '"foo\u20acbar"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '"foo\ud800bar"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py # unpaired surrogate -+ echo '"\u4321\u4321\u4321\u4321\u4321\u4321\u4321xy"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '"\u4321\u4321\u4321\u4321\u4321\u4321\u4321xyz"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '"\u4321\u4321\u4321\u4321\u4321\u4321\u4321xyzw"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '"\u4321\u4321\u4321\u4321\u4321\u4321\u4321xyzw......................................................................................................................................................................................................................................"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '"\u4321\u4321\u4321\u4321\u4321\u4321\u4321xyzw......................................................................................................................................................................................................................................!"' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ -+.PHONY: enc-array -+enc-array: jsoncbor -+ echo '[]' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '[ "foo", "bar", "quux" ]' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ # XXX: other lengths -+ echo '([[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{ foo: 123 }]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]])' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ -+.PHONY: enc-object -+enc-object: jsoncbor -+ echo '({})' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ foo: 123 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ foo: 123, bar: 234, quux: 345 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ foo: 123, bar: [ "foo", "bar", { baz: true } ], quux: 345 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14, o:15, p:16, q:17, r:18, s:19, t:20, u:21, v:22 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14, o:15, p:16, q:17, r:18, s:19, t:20, u:21, v:22, w:23 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14, o:15, p:16, q:17, r:18, s:19, t:20, u:21, v:22, w:23, x:24 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14, o:15, p:16, q:17, r:18, s:19, t:20, u:21, v:22, w:23, x:24, y:25 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({ a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10, k:11, l:12, m:13, n:14, o:15, p:16, q:17, r:18, s:19, t:20, u:21, v:22, w:23, x:24, y:25, z:26 })' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ echo '({foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:{foo:123}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}})' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -+ -+.PHONY: enc-misc -+enc-misc: jsoncbor -+ echo '({ jsonrpc: "2.0", id: "foo-1", method: "Add", params: { a: 123, b: 234 }})' | $(VALGRIND) -q ./jsoncbor -r js -w cbor | python2 cbordecode.py -diff --git a/dist/source/extras/cbor/README.rst b/dist/source/extras/cbor/README.rst -new file mode 100644 -index 0000000..1352b96 ---- /dev/null -+++ b/dist/source/extras/cbor/README.rst -@@ -0,0 +1,150 @@ -+============ -+CBOR binding -+============ -+ -+Overview -+======== -+ -+C functions to encode/decode values in CBOR format, and a simple command -+line utility to convert between JSON and CBOR. -+ -+To integrate CBOR into your application: -+ -+* Call ``duk_cbor_encode()`` and ``duk_cbor_decode()`` directly if a C API -+ is enough. -+ -+* Call ``duk_cbor_init()`` to register a global ``CBOR`` object with -+ ECMAScript bindings ``CBOR.encode()`` and ``CBOR.decode()``, roughly -+ matching https://github.com/paroga/cbor-js. -+ -+Basic usage of the ``jsoncbor`` conversion tool:: -+ -+ $ make jsoncbor -+ [...] -+ $ cat test.json | ./jsoncbor -e # writes CBOR to stdout -+ $ cat test.cbor | ./jsoncbor -d # writes JSON to stdout -+ -+CBOR objects are decoded into ECMAScript objects, with non-string keys -+coerced into strings. -+ -+Direct support for CBOR is likely to be included in the Duktape API in the -+future. This extra will then become unnecessary. -+ -+CBOR -+==== -+ -+CBOR is a standard format for JSON-like binary interchange. It is -+faster and smaller, and can encode more data types than JSON. In particular, -+binary data can be serialized without encoding e.g. in base-64. These -+properties make it useful for storing state files, IPC, etc. -+ -+Some CBOR shortcomings for preserving information: -+ -+* No property attribute or inheritance support. -+ -+* No DAGs or looped graphs. -+ -+* Array objects with properties lose their non-index properties. -+ -+* Array objects with gaps lose their gaps as they read back as undefined. -+ -+* Buffer objects and views lose much of their detail besides the raw data. -+ -+* ECMAScript strings cannot be fully represented; strings must be UTF-8. -+ -+* Functions and native objects lose most of their detail. -+ -+* CBOR tags are useful to provide soft decoding information, but the tags -+ are just integers from an IANA controlled space with no space for custom -+ tags. So tags cannot be easily used for private, application specific tags. -+ IANA allows reserving custom tags with little effort however, see -+ https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml. -+ -+Future work -+=========== -+ -+General: -+ -+* Add flags to control encode/decode behavior. -+ -+* Allow decoding with a trailer so that stream parsing is easier. -+ Similar change would be useful for JSON decoding. -+ -+* Reserve CBOR tag for missing value. -+ -+* Reserve other necessary CBOR tags. -+ -+* Explicit support for encoding with and without side effects (e.g. -+ skipping Proxy traps and getters). -+ -+* JSON encoding supports .toJSON(), maybe something like .toCBOR()? -+ -+* Optimize encoding and decoding more. -+ -+Encoding: -+ -+* Tagging of typed arrays: -+ https://datatracker.ietf.org/doc/draft-ietf-cbor-array-tags/. -+ Mixed endian encode must convert to e.g. little endian because -+ no mixed endian tag exists. -+ -+* Encoding typed arrays as integer arrays instead? -+ -+* Float16Array encoding support (once/if supported by main engine). -+ -+* Tagging of array gaps, once IANA reservation is complete: -+ https://github.com/svaarala/duktape/blob/master/doc/cbor-missing-tag.rst. -+ -+* Support 64-bit integer when encoding, e.g. up to 2^53? -+ -+* Definite-length object encoding even when object has more than 23 keys. -+ -+* Map/Set encoding (once supported in the main engine), maybe tagged -+ so they decode back into Map/Set. -+ -+* Bigint encoding (once supported in the main engine), as tagged byte -+ strings like in Python CBOR. -+ -+* String encoding options: combining surrogate pairs, tagging non-UTF-8 -+ byte strings so they decode back to string, using U+FFFD replacement, -+ etc. -+ -+* Detection of Symbols, encode them in a useful tagged form. -+ -+* Better encoding of functions. -+ -+* Hook for serialization, to allow caller to serialize values (especially -+ objects) in a context specific manner (e.g. serialize functions with -+ IPC metadata to allow them to be called remotely). Such a hook should -+ be able to emit tag(s) to mark custom values for decode processing. -+ -+Decoding: -+ -+* Typed array decoding support. Should decoder convert to host -+ endianness? -+ -+* Float16Array decoding support (once/if supported by main engine). -+ -+* Decoding objects with non-string keys, could be represented as a Map. -+ -+* Use bare objects and arrays when decoding? -+ -+* Use a Map rather than a plain object when decoding, which would allow -+ non-string keys. -+ -+* Bigint decoding (once supported in the main engine). -+ -+* Decoding of non-BMP codepoints into surrogate pairs. -+ -+* Decoding of Symbols when call site indicates it is safe. -+ -+* Hooking for revival, to allow caller to revive objects in a context -+ specific manner (e.g. revive serialized function objects into IPC -+ proxy functions). Such a hook should have access to encoding tags, -+ so that revival can depend on tags present. -+ -+* Option to compact decoded objects and arrays. -+ -+* Improve fastint decoding support, e.g. decode non-optimally encoded -+ integers as fastints, decode compatible floating point values as -+ fastints. -diff --git a/dist/source/extras/cbor/cbordecode.py b/dist/source/extras/cbor/cbordecode.py -new file mode 100644 -index 0000000..95db923 ---- /dev/null -+++ b/dist/source/extras/cbor/cbordecode.py -@@ -0,0 +1,24 @@ -+#!/usr/bin/env python2 -+ -+def main(): -+ import sys -+ import cbor -+ import json -+ -+ data = sys.stdin.read() -+ print('LEN: %d' % len(data)) -+ sys.stdout.flush() -+ print('HEX: ' + data.encode('hex')) -+ sys.stdout.flush() -+ doc = cbor.loads(data) -+ print('REPR: ' + repr(doc)) -+ sys.stdout.flush() -+ try: -+ print('JSON: ' + json.dumps(doc)) -+ sys.stdout.flush() -+ except: -+ print('JSON: cannot encode') -+ sys.stdout.flush() -+ -+if __name__ == '__main__': -+ main() -diff --git a/dist/source/extras/cbor/duk_cbor.c b/dist/source/extras/cbor/duk_cbor.c -new file mode 100644 -index 0000000..5304df6 ---- /dev/null -+++ b/dist/source/extras/cbor/duk_cbor.c -@@ -0,0 +1,2075 @@ -+/* -+ * CBOR bindings for Duktape. -+ * -+ * https://tools.ietf.org/html/rfc7049 -+ */ -+ -+#include -+#include -+#include "duktape.h" -+#include "duk_cbor.h" -+ -+/* #define DUK_CBOR_DPRINT */ -+/* #define DUK_CBOR_STRESS */ -+ -+#if 1 -+#define DUK_CBOR_ASSERT(x) do {} while (0) -+#else -+#include -+#include -+#define DUK_CBOR_ASSERT(x) do { \ -+ if (!(x)) { \ -+ fprintf(stderr, "ASSERT FAILED on %s:%d\n", __FILE__, __LINE__); \ -+ fflush(stderr); \ -+ abort(); \ -+ } \ -+ } while (0) -+#endif -+ -+#if 0 -+#define DUK_CBOR_LIKELY(x) __builtin_expect (!!(x), 1) -+#define DUK_CBOR_UNLIKELY(x) __builtin_expect (!!(x), 0) -+#define DUK_CBOR_INLINE inline -+#define DUK_CBOR_NOINLINE __attribute__((noinline)) -+#else -+#define DUK_CBOR_LIKELY(x) (x) -+#define DUK_CBOR_UNLIKELY(x) (x) -+#define DUK_CBOR_INLINE -+#define DUK_CBOR_NOINLINE -+#endif -+ -+/* #define DUK_CBOR_GCC_BUILTINS */ -+ -+/* Default behavior for encoding strings: use CBOR text string if string -+ * is UTF-8 compatible, otherwise use CBOR byte string. These defines -+ * can be used to force either type for all strings. Using text strings -+ * for non-UTF-8 data is technically invalid CBOR. -+ */ -+/* #define DUK_CBOR_TEXT_STRINGS */ -+/* #define DUK_CBOR_BYTE_STRINGS */ -+ -+/* Misc. defines. */ -+/* #define DUK_CBOR_PREFER_SIZE */ -+/* #define DUK_CBOR_DOUBLE_AS_IS */ -+/* #define DUK_CBOR_DECODE_FASTPATH */ -+ -+typedef struct { -+ duk_context *ctx; -+ duk_uint8_t *ptr; -+ duk_uint8_t *buf; -+ duk_uint8_t *buf_end; -+ duk_size_t len; -+ duk_idx_t idx_buf; -+} duk_cbor_encode_context; -+ -+typedef struct { -+ duk_context *ctx; -+ const duk_uint8_t *buf; -+ duk_size_t off; -+ duk_size_t len; -+} duk_cbor_decode_context; -+ -+typedef union { -+ duk_uint8_t x[8]; -+ duk_uint16_t s[4]; -+ duk_uint32_t i[2]; -+#if 0 -+ duk_uint64_t i64[1]; -+#endif -+ double d; -+} duk_cbor_dblunion; -+ -+typedef union { -+ duk_uint8_t x[4]; -+ duk_uint16_t s[2]; -+ duk_uint32_t i[1]; -+ float f; -+} duk_cbor_fltunion; -+ -+static void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx); -+static void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx); -+ -+/* -+ * Misc -+ */ -+ -+/* XXX: These are sometimes portability concerns and would be nice to expose -+ * from Duktape itself as portability helpers. -+ */ -+ -+static int duk__cbor_signbit(double d) { -+ return signbit(d); -+} -+ -+static int duk__cbor_fpclassify(double d) { -+ return fpclassify(d); -+} -+ -+static int duk__cbor_isnan(double d) { -+ return isnan(d); -+} -+ -+static int duk__cbor_isinf(double d) { -+ return isinf(d); -+} -+ -+static duk_uint32_t duk__cbor_double_to_uint32(double d) { -+ /* Out of range casts are undefined behavior, so caller must avoid. */ -+ DUK_CBOR_ASSERT(d >= 0.0 && d <= 4294967295.0); -+ return (duk_uint32_t) d; -+} -+ -+/* Endian detection. Technically happens at runtime, but in practice -+ * resolves at compile time to a constant and gets inlined. -+ */ -+#define DUK__CBOR_LITTLE_ENDIAN 1 -+#define DUK__CBOR_MIXED_ENDIAN 2 -+#define DUK__CBOR_BIG_ENDIAN 3 -+ -+static int duk__cbor_check_endian(void) { -+ duk_cbor_dblunion u; -+ -+ /* >>> struct.pack('>d', 1.23456789).encode('hex') -+ * '3ff3c0ca4283de1b' -+ */ -+ -+ u.d = 1.23456789; -+ if (u.x[0] == 0x1bU) { -+ return DUK__CBOR_LITTLE_ENDIAN; -+ } else if (u.x[0] == 0x3fU) { -+ return DUK__CBOR_BIG_ENDIAN; -+ } else if (u.x[0] == 0xcaU) { -+ return DUK__CBOR_MIXED_ENDIAN; -+ } else { -+ DUK_CBOR_ASSERT(0); -+ } -+ return 0; -+} -+ -+static DUK_CBOR_INLINE duk_uint16_t duk__cbor_bswap16(duk_uint16_t x) { -+#if defined(DUK_CBOR_GCC_BUILTINS) -+ return __builtin_bswap16(x); -+#else -+ /* XXX: matches, DUK_BSWAP16(), use that if exposed. */ -+ return (x >> 8) | (x << 8); -+#endif -+} -+ -+static DUK_CBOR_INLINE duk_uint32_t duk__cbor_bswap32(duk_uint32_t x) { -+#if defined(DUK_CBOR_GCC_BUILTINS) -+ return __builtin_bswap32(x); -+#else -+ /* XXX: matches, DUK_BSWAP32(), use that if exposed. */ -+ return (x >> 24) | ((x >> 8) & 0xff00UL) | ((x << 8) & 0xff0000UL) | (x << 24); -+#endif -+} -+ -+#if 0 -+static duk_uint64_t duk__cbor_bswap64(duk_uint64_t x) { -+ /* XXX */ -+} -+#endif -+ -+static DUK_CBOR_INLINE void duk__cbor_write_uint16_big(duk_uint8_t *p, duk_uint16_t x) { -+#if 0 -+ *p++ = (duk_uint8_t) ((x >> 8) & 0xffU); -+ *p++ = (duk_uint8_t) (x & 0xffU); -+#endif -+ duk_uint16_t a; -+ -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ case DUK__CBOR_MIXED_ENDIAN: -+ a = duk__cbor_bswap16(x); -+ (void) memcpy((void *) p, (const void *) &a, 2); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ a = x; -+ (void) memcpy((void *) p, (const void *) &a, 2); -+ break; -+ default: -+ DUK_CBOR_ASSERT(0); -+ } -+} -+ -+static DUK_CBOR_INLINE duk_uint16_t duk__cbor_read_uint16_big(const duk_uint8_t *p) { -+ duk_uint16_t a, x; -+ -+#if 0 -+ x = (((duk_uint16_t) p[0]) << 8U) + -+ ((duk_uint16_t) p[1]); -+#endif -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ case DUK__CBOR_MIXED_ENDIAN: -+ (void) memcpy((void *) &a, (const void *) p, 2); -+ x = duk__cbor_bswap16(a); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ (void) memcpy((void *) &a, (const void *) p, 2); -+ x = a; -+ break; -+ default: -+ DUK_CBOR_ASSERT(0); -+ x = 0; -+ } -+ return x; -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_write_uint32_big(duk_uint8_t *p, duk_uint32_t x) { -+#if 0 -+ *p++ = (duk_uint8_t) ((x >> 24) & 0xffU); -+ *p++ = (duk_uint8_t) ((x >> 16) & 0xffU); -+ *p++ = (duk_uint8_t) ((x >> 8) & 0xffU); -+ *p++ = (duk_uint8_t) (x & 0xffU); -+#endif -+ duk_uint32_t a; -+ -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ case DUK__CBOR_MIXED_ENDIAN: -+ a = duk__cbor_bswap32(x); -+ (void) memcpy((void *) p, (const void *) &a, 4); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ a = x; -+ (void) memcpy((void *) p, (const void *) &a, 4); -+ break; -+ default: -+ DUK_CBOR_ASSERT(0); -+ } -+} -+ -+static DUK_CBOR_INLINE duk_uint32_t duk__cbor_read_uint32_big(const duk_uint8_t *p) { -+ duk_uint32_t a, x; -+ -+#if 0 -+ x = (((duk_uint32_t) p[0]) << 24U) + -+ (((duk_uint32_t) p[1]) << 16U) + -+ (((duk_uint32_t) p[2]) << 8U) + -+ ((duk_uint32_t) p[3]); -+#endif -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ case DUK__CBOR_MIXED_ENDIAN: -+ (void) memcpy((void *) &a, (const void *) p, 4); -+ x = duk__cbor_bswap32(a); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ (void) memcpy((void *) &a, (const void *) p, 4); -+ x = a; -+ break; -+ default: -+ DUK_CBOR_ASSERT(0); -+ x = 0; -+ } -+ return x; -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_write_double_big(duk_uint8_t *p, double x) { -+ duk_cbor_dblunion u; -+ duk_uint32_t a, b; -+ -+ u.d = x; -+ -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+#if 0 -+ u.i64[0] = duk__cbor_bswap64(u.i64[0]); -+ (void) memcpy((void *) p, (const void *) u.x, 8); -+#endif -+ a = u.i[0]; -+ b = u.i[1]; -+ u.i[0] = duk__cbor_bswap32(b); -+ u.i[1] = duk__cbor_bswap32(a); -+ (void) memcpy((void *) p, (const void *) u.x, 8); -+ break; -+ case DUK__CBOR_MIXED_ENDIAN: -+ a = u.i[0]; -+ b = u.i[1]; -+ u.i[0] = duk__cbor_bswap32(a); -+ u.i[1] = duk__cbor_bswap32(b); -+ (void) memcpy((void *) p, (const void *) u.x, 8); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ (void) memcpy((void *) p, (const void *) u.x, 8); -+ break; -+ default: -+ DUK_CBOR_ASSERT(0); -+ } -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_write_float_big(duk_uint8_t *p, float x) { -+ duk_cbor_fltunion u; -+ duk_uint32_t a; -+ -+ u.f = x; -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ case DUK__CBOR_MIXED_ENDIAN: -+ a = u.i[0]; -+ u.i[0] = duk__cbor_bswap32(a); -+ (void) memcpy((void *) p, (const void *) u.x, 4); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ (void) memcpy((void *) p, (const void *) u.x, 4); -+ break; -+ default: -+ DUK_CBOR_ASSERT(0); -+ } -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_dblunion_host_to_little(duk_cbor_dblunion *u) { -+ duk_uint32_t a, b; -+ -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ /* HGFEDCBA -> HGFEDCBA */ -+ break; -+ case DUK__CBOR_MIXED_ENDIAN: -+ /* DCBAHGFE -> HGFEDCBA */ -+ a = u->i[0]; -+ b = u->i[1]; -+ u->i[0] = b; -+ u->i[1] = a; -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ /* ABCDEFGH -> HGFEDCBA */ -+#if 0 -+ u->i64[0] = duk__cbor_bswap64(u->i64[0]); -+#endif -+ a = u->i[0]; -+ b = u->i[1]; -+ u->i[0] = duk__cbor_bswap32(b); -+ u->i[1] = duk__cbor_bswap32(a); -+ break; -+ } -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_dblunion_little_to_host(duk_cbor_dblunion *u) { -+ duk__cbor_dblunion_host_to_little(u); -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_dblunion_host_to_big(duk_cbor_dblunion *u) { -+ duk_uint32_t a, b; -+ -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ /* HGFEDCBA -> ABCDEFGH */ -+#if 0 -+ u->i64[0] = duk__cbor_bswap64(u->i64[0]); -+#else -+ a = u->i[0]; -+ b = u->i[1]; -+ u->i[0] = duk__cbor_bswap32(b); -+ u->i[1] = duk__cbor_bswap32(a); -+#endif -+ break; -+ case DUK__CBOR_MIXED_ENDIAN: -+ /* DCBAHGFE -> ABCDEFGH */ -+ a = u->i[0]; -+ b = u->i[1]; -+ u->i[0] = duk__cbor_bswap32(a); -+ u->i[1] = duk__cbor_bswap32(b); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ /* ABCDEFGH -> ABCDEFGH */ -+ break; -+ } -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_dblunion_big_to_host(duk_cbor_dblunion *u) { -+ duk__cbor_dblunion_host_to_big(u); -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_fltunion_host_to_big(duk_cbor_fltunion *u) { -+ switch (duk__cbor_check_endian()) { -+ case DUK__CBOR_LITTLE_ENDIAN: -+ case DUK__CBOR_MIXED_ENDIAN: -+ /* DCBA -> ABCD */ -+ u->i[0] = duk__cbor_bswap32(u->i[0]); -+ break; -+ case DUK__CBOR_BIG_ENDIAN: -+ /* ABCD -> ABCD */ -+ break; -+ } -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_fltunion_big_to_host(duk_cbor_fltunion *u) { -+ duk__cbor_fltunion_host_to_big(u); -+} -+ -+/* -+ * Encoding -+ */ -+ -+static void duk__cbor_encode_error(duk_cbor_encode_context *enc_ctx) { -+ (void) duk_type_error(enc_ctx->ctx, "cbor encode error"); -+} -+ -+/* Check whether a string is UTF-8 compatible or not. */ -+static int duk__cbor_is_utf8_compatible(const duk_uint8_t *buf, duk_size_t len) { -+ duk_size_t i = 0; -+#if !defined(DUK_CBOR_PREFER_SIZE) -+ duk_size_t len_safe; -+#endif -+ -+ /* Many practical strings are ASCII only, so use a fast path check -+ * to check chunks of bytes at once with minimal branch cost. -+ */ -+#if !defined(DUK_CBOR_PREFER_SIZE) -+ len_safe = len & ~0x03UL; -+ for (; i < len_safe; i += 4) { -+ duk_uint8_t t = buf[i] | buf[i + 1] | buf[i + 2] | buf[i + 3]; -+ if (DUK_CBOR_UNLIKELY((t & 0x80U) != 0U)) { -+ /* At least one byte was outside 0x00-0x7f, break -+ * out to slow path (and remain there). -+ * -+ * XXX: We could also deal with the problem character -+ * and resume fast path later. -+ */ -+ break; -+ } -+ } -+#endif -+ -+ for (; i < len;) { -+ duk_uint8_t t; -+ duk_size_t left; -+ duk_size_t ncont; -+ duk_uint32_t cp; -+ duk_uint32_t mincp; -+ -+ t = buf[i++]; -+ if (DUK_CBOR_LIKELY((t & 0x80U) == 0U)) { -+ /* Fast path, ASCII. */ -+ continue; -+ } -+ -+ /* Non-ASCII start byte, slow path. -+ * -+ * 10xx xxxx -> continuation byte -+ * 110x xxxx + 1*CONT -> [0x80, 0x7ff] -+ * 1110 xxxx + 2*CONT -> [0x800, 0xffff], must reject [0xd800,0xdfff] -+ * 1111 0xxx + 3*CONT -> [0x10000, 0x10ffff] -+ */ -+ left = len - i; -+ if (t <= 0xdfU) { /* 1101 1111 = 0xdf */ -+ if (t <= 0xbfU) { /* 1011 1111 = 0xbf */ -+ return 0; -+ } -+ ncont = 1; -+ mincp = 0x80UL; -+ cp = t & 0x1fU; -+ } else if (t <= 0xefU) { /* 1110 1111 = 0xef */ -+ ncont = 2; -+ mincp = 0x800UL; -+ cp = t & 0x0fU; -+ } else if (t <= 0xf7U) { /* 1111 0111 = 0xf7 */ -+ ncont = 3; -+ mincp = 0x10000UL; -+ cp = t & 0x07U; -+ } else { -+ return 0; -+ } -+ if (left < ncont) { -+ return 0; -+ } -+ while (ncont > 0U) { -+ t = buf[i++]; -+ if ((t & 0xc0U) != 0x80U) { /* 10xx xxxx */ -+ return 0; -+ } -+ cp = (cp << 6) + (t & 0x3fU); -+ ncont--; -+ } -+ if (cp < mincp || cp > 0x10ffffUL || (cp >= 0xd800UL && cp <= 0xdfffUL)) { -+ return 0; -+ } -+ } -+ -+ return 1; -+} -+ -+/* Check that a size_t is in uint32 range to avoid out-of-range casts. */ -+static void duk__cbor_encode_sizet_uint32_check(duk_cbor_encode_context *enc_ctx, duk_size_t len) { -+ if (DUK_CBOR_UNLIKELY(sizeof(duk_size_t) > sizeof(duk_uint32_t) && len > (duk_size_t) DUK_UINT32_MAX)) { -+ duk__cbor_encode_error(enc_ctx); -+ } -+} -+ -+static DUK_CBOR_NOINLINE void duk__cbor_encode_ensure_slowpath(duk_cbor_encode_context *enc_ctx, duk_size_t len) { -+ duk_size_t oldlen; -+ duk_size_t minlen; -+ duk_size_t newlen; -+ duk_uint8_t *p_new; -+ duk_size_t old_data_len; -+ -+ DUK_CBOR_ASSERT(enc_ctx->ptr >= enc_ctx->buf); -+ DUK_CBOR_ASSERT(enc_ctx->buf_end >= enc_ctx->ptr); -+ DUK_CBOR_ASSERT(enc_ctx->buf_end >= enc_ctx->buf); -+ -+ /* Overflow check. -+ * -+ * Limit example: 0xffffffffUL / 2U = 0x7fffffffUL, we reject >= 0x80000000UL. -+ */ -+ oldlen = enc_ctx->len; -+ minlen = oldlen + len; -+ if (DUK_CBOR_UNLIKELY(oldlen > DUK_SIZE_MAX / 2U || minlen < oldlen)) { -+ duk__cbor_encode_error(enc_ctx); -+ } -+ -+#if defined(DUK_CBOR_STRESS) -+ newlen = oldlen + 1U; -+#else -+ newlen = oldlen * 2U; -+#endif -+ DUK_CBOR_ASSERT(newlen >= oldlen); -+ -+ if (minlen > newlen) { -+ newlen = minlen; -+ } -+ DUK_CBOR_ASSERT(newlen >= oldlen); -+ DUK_CBOR_ASSERT(newlen >= minlen); -+ DUK_CBOR_ASSERT(newlen > 0U); -+ -+#if defined(DUK_CBOR_DPRINT) -+ fprintf(stderr, "cbor encode buffer resized to %ld\n", (long) newlen); -+#endif -+ -+ p_new = (duk_uint8_t *) duk_resize_buffer(enc_ctx->ctx, enc_ctx->idx_buf, newlen); -+ DUK_CBOR_ASSERT(p_new != NULL); -+ old_data_len = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf); -+ enc_ctx->buf = p_new; -+ enc_ctx->buf_end = p_new + newlen; -+ enc_ctx->ptr = p_new + old_data_len; -+ enc_ctx->len = newlen; -+} -+ -+static DUK_CBOR_INLINE void duk__cbor_encode_ensure(duk_cbor_encode_context *enc_ctx, duk_size_t len) { -+ if (DUK_CBOR_LIKELY((duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr) >= len)) { -+ return; -+ } -+ duk__cbor_encode_ensure_slowpath(enc_ctx, len); -+} -+ -+static duk_size_t duk__cbor_get_reserve(duk_cbor_encode_context *enc_ctx) { -+ DUK_CBOR_ASSERT(enc_ctx->ptr >= enc_ctx->buf); -+ DUK_CBOR_ASSERT(enc_ctx->ptr <= enc_ctx->buf_end); -+ return (duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr); -+} -+ -+static void duk__cbor_encode_uint32(duk_cbor_encode_context *enc_ctx, duk_uint32_t u, duk_uint8_t base) { -+ duk_uint8_t *p; -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 4); -+ -+ p = enc_ctx->ptr; -+ if (DUK_CBOR_LIKELY(u <= 23U)) { -+ *p++ = (duk_uint8_t) (base + (duk_uint8_t) u); -+ } else if (u <= 0xffUL) { -+ *p++ = base + 0x18U; -+ *p++ = (duk_uint8_t) u; -+ } else if (u <= 0xffffUL) { -+ *p++ = base + 0x19U; -+ duk__cbor_write_uint16_big(p, (duk_uint16_t) u); -+ p += 2; -+ } else { -+ *p++ = base + 0x1aU; -+ duk__cbor_write_uint32_big(p, u); -+ p += 4; -+ } -+ enc_ctx->ptr = p; -+} -+ -+#if defined(DUK_CBOR_DOUBLE_AS_IS) -+static void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) { -+ duk_uint8_t *p; -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); -+ -+ p = enc_ctx->ptr; -+ *p++ = 0xfbU; -+ duk__cbor_write_double_big(p, d); -+ p += 8; -+ enc_ctx->ptr = p; -+} -+#else /* DUK_CBOR_DOUBLE_AS_IS */ -+static void duk__cbor_encode_double_fp(duk_cbor_encode_context *enc_ctx, double d) { -+ duk_cbor_dblunion u; -+ duk_uint16_t u16; -+ duk_int16_t exp; -+ duk_uint8_t *p; -+ -+ DUK_CBOR_ASSERT(duk__cbor_fpclassify(d) != FP_ZERO); -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); -+ -+ /* Organize into little endian (no-op if platform is little endian). */ -+ u.d = d; -+ duk__cbor_dblunion_host_to_little(&u); -+ -+ /* Check if 'd' can represented as a normal half-float. -+ * Denormal half-floats could also be used, but that check -+ * isn't done now (denormal half-floats are decoded of course). -+ * So just check exponent range and that at most 10 significant -+ * bits (excluding implicit leading 1) are used in 'd'. -+ */ -+ u16 = (((duk_uint16_t) u.x[7]) << 8) | ((duk_uint16_t) u.x[6]); -+ exp = (duk_int16_t) ((u16 & 0x7ff0U) >> 4) - 1023; -+ -+ if (exp >= -14 && exp <= 15) { -+ /* Half-float normal exponents (excl. denormals). -+ * -+ * 7 6 5 4 3 2 1 0 (LE index) -+ * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm -+ * half: seeeee mmmm mmmmmm00 00000000 00000000 00000000 00000000 00000000 -+ */ -+ int use_half_float; -+ -+ use_half_float = -+ (u.x[0] == 0 && u.x[1] == 0 && u.x[2] == 0 && u.x[3] == 0 && -+ u.x[4] == 0 && (u.x[5] & 0x03U) == 0); -+ -+ if (use_half_float) { -+ duk_uint32_t t; -+ -+ exp += 15; -+ t = (duk_uint32_t) (u.x[7] & 0x80U) << 8; -+ t += (duk_uint32_t) exp << 10; -+ t += ((duk_uint32_t) u.x[6] & 0x0fU) << 6; -+ t += ((duk_uint32_t) u.x[5]) >> 2; -+ -+ /* seeeeemm mmmmmmmm */ -+ p = enc_ctx->ptr; -+ *p++ = 0xf9U; -+ duk__cbor_write_uint16_big(p, (duk_uint16_t) t); -+ p += 2; -+ enc_ctx->ptr = p; -+ return; -+ } -+ } -+ -+ /* Same check for plain float. Also no denormal support here. */ -+ if (exp >= -126 && exp <= 127) { -+ /* Float normal exponents (excl. denormals). -+ * -+ * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm -+ * float: seeee eeeemmmm mmmmmmmm mmmmmmmm mmm00000 00000000 00000000 00000000 -+ */ -+ int use_float; -+ duk_float_t d_float; -+ -+ /* We could do this explicit mantissa check, but doing -+ * a double-float-double cast is fine because we've -+ * already verified that the exponent is in range so -+ * that the narrower cast is not undefined behavior. -+ */ -+#if 0 -+ use_float = -+ (u.x[0] == 0 && u.x[1] == 0 && u.x[2] == 0 && (u.x[3] & 0xe0U) == 0); -+#endif -+ d_float = (duk_float_t) d; -+ use_float = ((duk_double_t) d_float == d); -+ if (use_float) { -+ p = enc_ctx->ptr; -+ *p++ = 0xfaU; -+ duk__cbor_write_float_big(p, d_float); -+ p += 4; -+ enc_ctx->ptr = p; -+ return; -+ } -+ } -+ -+ /* Special handling for NaN and Inf which we want to encode as -+ * half-floats. They share the same (maximum) exponent. -+ */ -+ if (exp == 1024) { -+ DUK_CBOR_ASSERT(duk__cbor_isnan(d) || duk__cbor_isinf(d)); -+ p = enc_ctx->ptr; -+ *p++ = 0xf9U; -+ if (duk__cbor_isnan(d)) { -+ /* Shortest NaN encoding is using a half-float. Lose the -+ * exact NaN bits in the process. IEEE double would be -+ * 7ff8 0000 0000 0000, i.e. a quiet NaN in most architectures -+ * (https://en.wikipedia.org/wiki/NaN#Encoding). The -+ * equivalent half float is 7e00. -+ */ -+ *p++ = 0x7eU; -+ } else { -+ /* Shortest +/- Infinity encoding is using a half-float. */ -+ if (duk__cbor_signbit(d)) { -+ *p++ = 0xfcU; -+ } else { -+ *p++ = 0x7cU; -+ } -+ } -+ *p++ = 0x00U; -+ enc_ctx->ptr = p; -+ return; -+ } -+ -+ /* Cannot use half-float or float, encode as full IEEE double. */ -+ p = enc_ctx->ptr; -+ *p++ = 0xfbU; -+ duk__cbor_write_double_big(p, d); -+ p += 8; -+ enc_ctx->ptr = p; -+} -+ -+static void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) { -+ duk_uint8_t *p; -+ double d_floor; -+ -+ /* Integers and floating point values of all types are conceptually -+ * equivalent in CBOR. Try to always choose the shortest encoding -+ * which is not always immediately obvious. For example, NaN and Inf -+ * can be most compactly represented as a half-float (assuming NaN -+ * bits are not preserved), and 0x1'0000'0000 as a single precision -+ * float. Shortest forms in preference order (prefer integer over -+ * float when equal length): -+ * -+ * uint 1 byte [0,23] (not -0) -+ * sint 1 byte [-24,-1] -+ * uint+1 2 bytes [24,255] -+ * sint+1 2 bytes [-256,-25] -+ * uint+2 3 bytes [256,65535] -+ * sint+2 3 bytes [-65536,-257] -+ * half-float 3 bytes -0, NaN, +/- Infinity, range [-65504,65504] -+ * uint+4 5 bytes [65536,4294967295] -+ * sint+4 5 bytes [-4294967296,-258] -+ * float 5 bytes range [-(1 - 2^(-24)) * 2^128, (1 - 2^(-24)) * 2^128] -+ * uint+8 9 bytes [4294967296,18446744073709551615] -+ * sint+8 9 bytes [-18446744073709551616,-4294967297] -+ * double 9 bytes -+ * -+ * For whole numbers (compatible with integers): -+ * - 1-byte or 2-byte uint/sint representation is preferred for -+ * [-256,255]. -+ * - 3-byte uint/sint is preferred for [-65536,65535]. Half floats -+ * are never preferred because they have the same length. -+ * - 5-byte uint/sint is preferred for [-4294967296,4294967295]. -+ * Single precision floats are never preferred, and half-floats -+ * don't reach above the 3-byte uint/sint range so they're never -+ * preferred. -+ * - So, for all integers up to signed/unsigned 32-bit range the -+ * preferred encoding is always an integer uint/sint. -+ * - For integers above 32 bits the situation is more complicated. -+ * Half-floats are never useful for them because of their limited -+ * range, but IEEE single precision floats (5 bytes encoded) can -+ * represent some integers between the 32-bit and 64-bit ranges -+ * which require 9 bytes as a uint/sint. -+ * -+ * For floating point values not compatible with integers, the -+ * preferred encoding is quite clear: -+ * - For +Inf/-Inf use half-float. -+ * - For NaN use a half-float, assuming NaN bits ("payload") is -+ * not worth preserving. Duktape doesn't in general guarantee -+ * preservation of the NaN payload so using a half-float seems -+ * consistent with that. -+ * - For remaining values, prefer the shortest form which doesn't -+ * lose any precision. For normal half-floats and single precision -+ * floats this is simple: just check exponent and mantissa bits -+ * using a fixed mask. For denormal half-floats and single -+ * precision floats the check is a bit more complicated: a normal -+ * IEEE double can sometimes be represented as a denormal -+ * half-float or single precision float. -+ * -+ * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#IEEE_754_half-precision_binary_floating-point_format:_binary16 -+ */ -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); -+ -+ /* Most important path is integers. The floor() test will be true -+ * for Inf too (but not NaN). -+ */ -+ d_floor = floor(d); /* identity if d is +/- 0.0, NaN, or +/- Infinity */ -+ if (DUK_CBOR_LIKELY(d_floor == d)) { -+ DUK_CBOR_ASSERT(!duk__cbor_isnan(d)); /* NaN == NaN compares false. */ -+ if (duk__cbor_signbit(d)) { -+ if (d >= -4294967296.0) { -+ d = -1.0 - d; -+ if (d >= 0.0) { -+ DUK_CBOR_ASSERT(d >= 0.0); -+ duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x20U); -+ return; -+ } -+ -+ /* Input was negative zero, d == -1.0 < 0.0. -+ * Shortest -0 is using half-float. -+ */ -+ p = enc_ctx->ptr; -+ *p++ = 0xf9U; -+ *p++ = 0x80U; -+ *p++ = 0x00U; -+ enc_ctx->ptr = p; -+ return; -+ } -+ } else { -+ if (d <= 4294967295.0) { -+ /* Positive zero needs no special handling. */ -+ DUK_CBOR_ASSERT(d >= 0.0); -+ duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x00U); -+ return; -+ } -+ } -+ } -+ -+ /* 64-bit integers are not supported at present. So -+ * we also don't need to deal with choosing between a -+ * 64-bit uint/sint representation vs. IEEE double or -+ * float. -+ */ -+ -+ DUK_CBOR_ASSERT(duk__cbor_fpclassify(d) != FP_ZERO); -+ duk__cbor_encode_double_fp(enc_ctx, d); -+} -+#endif /* DUK_CBOR_DOUBLE_AS_IS */ -+ -+static void duk__cbor_encode_string_top(duk_cbor_encode_context *enc_ctx) { -+ const duk_uint8_t *str; -+ duk_size_t len; -+ duk_uint8_t *p; -+ -+ /* CBOR differentiates between UTF-8 text strings and byte strings. -+ * Text strings MUST be valid UTF-8, so not all Duktape strings can -+ * be encoded as valid CBOR text strings. Possible behaviors: -+ * -+ * 1. Use text string when input is valid UTF-8, otherwise use -+ * byte string (maybe tagged to indicate it was an extended -+ * UTF-8 string). -+ * 2. Always use text strings, but sanitize input string so that -+ * invalid UTF-8 is replaced with U+FFFD for example. Combine -+ * surrogates whenever possible. -+ * 3. Always use byte strings. This is simple and produces valid -+ * CBOR, but isn't ideal for interoperability. -+ * 4. Always use text strings, even for invalid UTF-8 such as -+ * codepoints in the surrogate pair range. This is simple but -+ * produces technically invalid CBOR for non-UTF-8 strings which -+ * may affect interoperability. -+ * -+ * Current default is 1; can be changed with defines. -+ */ -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); -+ -+ str = (const duk_uint8_t *) duk_require_lstring(enc_ctx->ctx, -1, &len); -+ if (duk_is_symbol(enc_ctx->ctx, -1)) { -+ /* Symbols, encode as an empty table for now. This matches -+ * the behavior of cbor-js. -+ * -+ * XXX: Maybe encode String() coercion with a tag? -+ * XXX: Option to keep enough information to recover -+ * Symbols when decoding (this is not always desirable). -+ */ -+ p = enc_ctx->ptr; -+ *p++ = 0xa0U; -+ enc_ctx->ptr = p; -+ return; -+ } -+ -+ duk__cbor_encode_sizet_uint32_check(enc_ctx, len); -+#if defined(DUK_CBOR_TEXT_STRINGS) -+ duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x60U); -+#elif defined(DUK_CBOR_BYTE_STRINGS) -+ duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U); -+#else -+ duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, -+ (DUK_CBOR_LIKELY(duk__cbor_is_utf8_compatible(str, len)) ? 0x60U : 0x40U)); -+#endif -+ duk__cbor_encode_ensure(enc_ctx, len); -+ p = enc_ctx->ptr; -+ (void) memcpy((void *) p, (const void *) str, len); -+ p += len; -+ enc_ctx->ptr = p; -+} -+ -+static void duk__cbor_encode_object(duk_cbor_encode_context *enc_ctx) { -+ duk_uint8_t *buf; -+ duk_size_t len; -+ duk_uint8_t *p; -+ duk_size_t i; -+ duk_size_t off_ib; -+ duk_uint32_t count; -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); -+ -+ /* XXX: Support for specific built-ins like Date and RegExp. */ -+ if (duk_is_array(enc_ctx->ctx, -1)) { -+ /* Shortest encoding for arrays >= 256 in length is actually -+ * the indefinite length one (3 or more bytes vs. 2 bytes). -+ * We still use the definite length version because it is -+ * more decoding friendly. -+ */ -+ len = duk_get_length(enc_ctx->ctx, -1); -+ duk__cbor_encode_sizet_uint32_check(enc_ctx, len); -+ duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x80U); -+ for (i = 0; i < len; i++) { -+ duk_get_prop_index(enc_ctx->ctx, -1, (duk_uarridx_t) i); -+ duk__cbor_encode_value(enc_ctx); -+ } -+ } else if (duk_is_buffer_data(enc_ctx->ctx, -1)) { -+ /* XXX: Tag buffer data? -+ * XXX: Encode typed arrays as integer arrays rather -+ * than buffer data as is? -+ */ -+ buf = (duk_uint8_t *) duk_require_buffer_data(enc_ctx->ctx, -1, &len); -+ duk__cbor_encode_sizet_uint32_check(enc_ctx, len); -+ duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U); -+ duk__cbor_encode_ensure(enc_ctx, len); -+ p = enc_ctx->ptr; -+ (void) memcpy((void *) p, (const void *) buf, len); -+ p += len; -+ enc_ctx->ptr = p; -+ } else { -+ /* We don't know the number of properties in advance -+ * but would still like to encode at least small -+ * objects without indefinite length. Emit an -+ * indefinite length byte initially, and if the final -+ * property count is small enough to also fit in one -+ * byte, backpatch it later. Otherwise keep the -+ * indefinite length. This works well up to 23 -+ * properties which is practical and good enough. -+ */ -+ off_ib = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf); /* XXX: get_offset? */ -+ count = 0U; -+ p = enc_ctx->ptr; -+ *p++ = 0xa0U + 0x1fU; /* indefinite length */ -+ enc_ctx->ptr = p; -+ duk_enum(enc_ctx->ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); -+ while (duk_next(enc_ctx->ctx, -1, 1 /*get_value*/)) { -+ duk_insert(enc_ctx->ctx, -2); /* [ ... key value ] -> [ ... value key ] */ -+ duk__cbor_encode_value(enc_ctx); -+ duk__cbor_encode_value(enc_ctx); -+ count++; -+ if (count == 0U) { -+ duk__cbor_encode_error(enc_ctx); -+ } -+ } -+ duk_pop(enc_ctx->ctx); -+ if (count <= 0x17U) { -+ DUK_CBOR_ASSERT(off_ib < enc_ctx->len); -+ enc_ctx->buf[off_ib] = 0xa0U + (duk_uint8_t) count; -+ } else { -+ duk__cbor_encode_ensure(enc_ctx, 1); -+ p = enc_ctx->ptr; -+ *p++ = 0xffU; /* break */ -+ enc_ctx->ptr = p; -+ } -+ } -+} -+ -+static void duk__cbor_encode_buffer(duk_cbor_encode_context *enc_ctx) { -+ duk_uint8_t *buf; -+ duk_size_t len; -+ duk_uint8_t *p; -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); -+ -+ /* Tag buffer data? */ -+ buf = (duk_uint8_t *) duk_require_buffer(enc_ctx->ctx, -1, &len); -+ duk__cbor_encode_sizet_uint32_check(enc_ctx, len); -+ duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U); -+ duk__cbor_encode_ensure(enc_ctx, len); -+ p = enc_ctx->ptr; -+ (void) memcpy((void *) p, (const void *) buf, len); -+ p += len; -+ enc_ctx->ptr = p; -+} -+ -+static void duk__cbor_encode_pointer(duk_cbor_encode_context *enc_ctx) { -+ /* Pointers (void *) are challenging to encode. They can't -+ * be relied to be even 64-bit integer compatible (there are -+ * pointer models larger than that), nor can floats encode -+ * them. They could be encoded as strings (%p format) but -+ * that's not portable. They could be encoded as direct memory -+ * representations. Recovering pointers is non-portable in any -+ * case but it would be nice to be able to detect and recover -+ * compatible pointers. -+ * -+ * For now, encode as "(%p)" string, matching JX. There doesn't -+ * seem to be an appropriate tag, so pointers don't currently -+ * survive a CBOR encode/decode roundtrip intact. -+ */ -+ const char *ptr; -+ -+ ptr = duk_to_string(enc_ctx->ctx, -1); -+ DUK_CBOR_ASSERT(ptr != NULL); -+ duk_push_sprintf(enc_ctx->ctx, "(%s)", ptr); -+ duk_remove(enc_ctx->ctx, -2); -+ duk__cbor_encode_string_top(enc_ctx); -+} -+ -+static void duk__cbor_encode_lightfunc(duk_cbor_encode_context *enc_ctx) { -+ duk_uint8_t *p; -+ -+ /* Caller must ensure space. */ -+ DUK_CBOR_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); -+ -+ /* For now encode as an empty object. */ -+ p = enc_ctx->ptr; -+ *p++ = 0xa0U; -+ enc_ctx->ptr = p; -+} -+ -+static void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx) { -+ duk_uint8_t *p; -+ -+ /* Encode/decode cycle currently loses some type information. -+ * This can be improved by registering custom tags with IANA. -+ */ -+ -+ /* When working with deeply recursive structures, this is important -+ * to ensure there's no effective depth limit. -+ */ -+ duk_require_stack(enc_ctx->ctx, 4); -+ -+ /* Reserve space for up to 64-bit types (1 initial byte + 8 -+ * followup bytes). This allows encoding of integers, floats, -+ * string/buffer length fields, etc without separate checks -+ * in each code path. -+ */ -+ duk__cbor_encode_ensure(enc_ctx, 1 + 8); -+ -+ switch (duk_get_type(enc_ctx->ctx, -1)) { -+ case DUK_TYPE_UNDEFINED: { -+ p = enc_ctx->ptr; -+ *p++ = 0xf7; -+ enc_ctx->ptr = p; -+ break; -+ } -+ case DUK_TYPE_NULL: { -+ p = enc_ctx->ptr; -+ *p++ = 0xf6; -+ enc_ctx->ptr = p; -+ break; -+ } -+ case DUK_TYPE_BOOLEAN: { -+ duk_uint8_t u8 = duk_get_boolean(enc_ctx->ctx, -1) ? 0xf5U : 0xf4U; -+ p = enc_ctx->ptr; -+ *p++ = u8; -+ enc_ctx->ptr = p; -+ break; -+ } -+ case DUK_TYPE_NUMBER: { -+ duk__cbor_encode_double(enc_ctx, duk_get_number(enc_ctx->ctx, -1)); -+ break; -+ } -+ case DUK_TYPE_STRING: { -+ duk__cbor_encode_string_top(enc_ctx); -+ break; -+ } -+ case DUK_TYPE_OBJECT: { -+ duk__cbor_encode_object(enc_ctx); -+ break; -+ } -+ case DUK_TYPE_BUFFER: { -+ duk__cbor_encode_buffer(enc_ctx); -+ break; -+ } -+ case DUK_TYPE_POINTER: { -+ duk__cbor_encode_pointer(enc_ctx); -+ break; -+ } -+ case DUK_TYPE_LIGHTFUNC: { -+ duk__cbor_encode_lightfunc(enc_ctx); -+ break; -+ } -+ case DUK_TYPE_NONE: -+ default: -+ goto fail; -+ } -+ -+ duk_pop(enc_ctx->ctx); -+ return; -+ -+ fail: -+ duk__cbor_encode_error(enc_ctx); -+} -+ -+/* -+ * Decoding -+ */ -+ -+static void duk__cbor_req_stack(duk_cbor_decode_context *dec_ctx) { -+ duk_require_stack(dec_ctx->ctx, 4); -+} -+ -+static void duk__cbor_decode_error(duk_cbor_decode_context *dec_ctx) { -+ (void) duk_type_error(dec_ctx->ctx, "cbor decode error"); -+} -+ -+static duk_uint8_t duk__cbor_decode_readbyte(duk_cbor_decode_context *dec_ctx) { -+ DUK_CBOR_ASSERT(dec_ctx->off <= dec_ctx->len); -+ if (DUK_CBOR_UNLIKELY(dec_ctx->len - dec_ctx->off < 1U)) { -+ duk__cbor_decode_error(dec_ctx); -+ } -+ return dec_ctx->buf[dec_ctx->off++]; -+} -+ -+static duk_uint16_t duk__cbor_decode_read_u16(duk_cbor_decode_context *dec_ctx) { -+ duk_uint16_t res; -+ -+ if (DUK_CBOR_UNLIKELY(dec_ctx->len - dec_ctx->off < 2U)) { -+ duk__cbor_decode_error(dec_ctx); -+ } -+ res = duk__cbor_read_uint16_big(dec_ctx->buf + dec_ctx->off); -+ dec_ctx->off += 2; -+ return res; -+} -+ -+static duk_uint32_t duk__cbor_decode_read_u32(duk_cbor_decode_context *dec_ctx) { -+ duk_uint32_t res; -+ -+ if (DUK_CBOR_UNLIKELY(dec_ctx->len - dec_ctx->off < 4U)) { -+ duk__cbor_decode_error(dec_ctx); -+ } -+ res = duk__cbor_read_uint32_big(dec_ctx->buf + dec_ctx->off); -+ dec_ctx->off += 4; -+ return res; -+} -+ -+static duk_uint8_t duk__cbor_decode_peekbyte(duk_cbor_decode_context *dec_ctx) { -+ if (DUK_CBOR_UNLIKELY(dec_ctx->off >= dec_ctx->len)) { -+ duk__cbor_decode_error(dec_ctx); -+ } -+ return dec_ctx->buf[dec_ctx->off]; -+} -+ -+static void duk__cbor_decode_rewind(duk_cbor_decode_context *dec_ctx, duk_size_t len) { -+ DUK_CBOR_ASSERT(len <= dec_ctx->off); /* Caller must ensure. */ -+ dec_ctx->off -= len; -+} -+ -+#if 0 -+static void duk__cbor_decode_ensure(duk_cbor_decode_context *dec_ctx, duk_size_t len) { -+ if (dec_ctx->off + len > dec_ctx->len) { -+ duk__cbor_decode_error(dec_ctx); -+ } -+} -+#endif -+ -+static const duk_uint8_t *duk__cbor_decode_consume(duk_cbor_decode_context *dec_ctx, duk_size_t len) { -+ DUK_CBOR_ASSERT(dec_ctx->off <= dec_ctx->len); -+ if (DUK_CBOR_LIKELY(dec_ctx->len - dec_ctx->off >= len)) { -+ const duk_uint8_t *res = dec_ctx->buf + dec_ctx->off; -+ dec_ctx->off += len; -+ return res; -+ } -+ -+ duk__cbor_decode_error(dec_ctx); /* Not enough input. */ -+ return NULL; -+} -+ -+static int duk__cbor_decode_checkbreak(duk_cbor_decode_context *dec_ctx) { -+ if (duk__cbor_decode_peekbyte(dec_ctx) == 0xffU) { -+ DUK_CBOR_ASSERT(dec_ctx->off < dec_ctx->len); -+ dec_ctx->off++; -+#if 0 -+ (void) duk__cbor_decode_readbyte(dec_ctx); -+#endif -+ return 1; -+ } -+ return 0; -+} -+ -+static void duk__cbor_decode_push_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_bool_t negative) { -+ duk_uint8_t ai; -+ duk_uint32_t t, t1, t2; -+#if 0 -+ duk_uint64_t t3; -+#endif -+ duk_double_t d1, d2; -+ duk_double_t d; -+ -+ ai = ib & 0x1fU; -+ if (ai <= 0x17U) { -+ t = ai; -+ goto shared_exit; -+ } -+ -+ switch (ai) { -+ case 0x18U: /* 1 byte */ -+ t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx); -+ goto shared_exit; -+ case 0x19U: /* 2 byte */ -+ t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx); -+ goto shared_exit; -+ case 0x1aU: /* 4 byte */ -+ t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); -+ goto shared_exit; -+ case 0x1bU: /* 8 byte */ -+ /* For uint64 it's important to handle the -1.0 part before -+ * casting to double: otherwise the adjustment might be lost -+ * in the cast. Uses: -1.0 - d <=> -(d + 1.0). -+ */ -+ t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); -+ t2 = t; -+ t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); -+ t1 = t; -+#if 0 -+ t3 = (duk_uint64_t) t2 * 0x100000000ULL + (duk_uint64_t) t1; -+ if (negative) { -+ if (t3 == DUK_UINT64_MAX) { -+ /* -(0xffff'ffff'ffff'ffffULL + 1) = -+ * -0x1'0000'0000'0000'0000 -+ * -+ * >>> -0x10000000000000000 -+ * -18446744073709551616L -+ */ -+ return -18446744073709551616.0; -+ } else { -+ return -((duk_double_t) (t3 + 1ULL)); -+ } -+ } else { -+ return (duk_double_t) t3; /* XXX: cast helper */ -+ } -+#endif -+#if 0 -+ t3 = (duk_uint64_t) t2 * 0x100000000ULL + (duk_uint64_t) t1; -+ if (negative) { -+ /* Simpler version: take advantage of the fact that -+ * 0xffff'ffff'ffff'ffff and 0x1'0000'0000'0000'0000 -+ * both round to 0x1'0000'0000'0000'0000: -+ * > (0xffffffffffffffff).toString(16) -+ * '10000000000000000' -+ * > (0x10000000000000000).toString(16) -+ * '10000000000000000' -+ * -+ * For the DUK_UINT64_MAX case we just skip the +1 -+ * increment to avoid wrapping; the result still -+ * comes out right for an IEEE double cast. -+ */ -+ if (t3 != DUK_UINT64_MAX) { -+ t3++; -+ } -+ return -((duk_double_t) t3); -+ } else { -+ return (duk_double_t) t3; /* XXX: cast helper */ -+ } -+#endif -+#if 1 -+ /* Use two double parts, avoids dependency on 64-bit type. -+ * Avoid precision loss carefully, especially when dealing -+ * with the required +1 for negative values. -+ * -+ * No fastint check for this path at present. -+ */ -+ d1 = (duk_double_t) t1; /* XXX: cast helpers */ -+ d2 = (duk_double_t) t2 * 4294967296.0; -+ if (negative) { -+ d1 += 1.0; -+ } -+ d = d2 + d1; -+ if (negative) { -+ d = -d; -+ } -+#endif -+ /* XXX: a push and check for fastint API would be nice */ -+ duk_push_number(dec_ctx->ctx, d); -+ return; -+ } -+ -+ duk__cbor_decode_error(dec_ctx); -+ return; -+ -+ shared_exit: -+ if (negative) { -+ /* XXX: a push and check for fastint API would be nice */ -+ if ((duk_uint_t) t <= (duk_uint_t) -(DUK_INT_MIN + 1)) { -+ duk_push_int(dec_ctx->ctx, -1 - ((duk_int_t) t)); -+ } else { -+ duk_push_number(dec_ctx->ctx, -1.0 - (duk_double_t) t); -+ } -+ } else { -+ duk_push_uint(dec_ctx->ctx, (duk_uint_t) t); -+ } -+} -+ -+static void duk__cbor_decode_skip_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) { -+ const duk_int8_t skips[32] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 8, -1, -1, -1, -1 -+ }; -+ duk_uint8_t ai; -+ duk_int8_t skip; -+ -+ ai = ib & 0x1fU; -+ skip = skips[ai]; -+ if (DUK_UNLIKELY(skip < 0)) { -+ duk__cbor_decode_error(dec_ctx); -+ } -+ duk__cbor_decode_consume(dec_ctx, (duk_size_t) skip); -+ return; -+} -+ -+static duk_uint32_t duk__cbor_decode_aival_uint32(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) { -+ duk_uint8_t ai; -+ duk_uint32_t t; -+ -+ ai = ib & 0x1fU; -+ if (ai <= 0x17U) { -+ return (duk_uint32_t) ai; -+ } -+ -+ switch (ai) { -+ case 0x18U: /* 1 byte */ -+ t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx); -+ return t; -+ case 0x19U: /* 2 byte */ -+ t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx); -+ return t; -+ case 0x1aU: /* 4 byte */ -+ t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); -+ return t; -+ case 0x1bU: /* 8 byte */ -+ t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); -+ if (t != 0U) { -+ break; -+ } -+ t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); -+ return t; -+ } -+ -+ duk__cbor_decode_error(dec_ctx); -+ return 0U; -+} -+ -+static void duk__cbor_decode_buffer(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) { -+ duk_uint32_t len; -+ duk_uint8_t *buf; -+ const duk_uint8_t *inp; -+ duk_uint8_t ib; -+ -+ ib = duk__cbor_decode_readbyte(dec_ctx); -+ if ((ib & 0xe0U) != expected_base) { -+ duk__cbor_decode_error(dec_ctx); -+ } -+ /* Indefinite format is rejected by the following on purpose. */ -+ len = duk__cbor_decode_aival_uint32(dec_ctx, ib); -+ inp = duk__cbor_decode_consume(dec_ctx, len); -+ /* XXX: duk_push_fixed_buffer_with_data() would be a nice API addition. */ -+ buf = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->ctx, (duk_size_t) len); -+ (void) memcpy((void *) buf, (const void *) inp, (size_t) len); -+} -+ -+static void duk__cbor_decode_join_buffers(duk_cbor_decode_context *dec_ctx, duk_idx_t count) { -+ duk_size_t total_size = 0; -+ duk_idx_t top = duk_get_top(dec_ctx->ctx); -+ duk_idx_t base = top - count; /* count is >= 1 */ -+ duk_idx_t idx; -+ duk_uint8_t *p = NULL; -+ -+ DUK_CBOR_ASSERT(count >= 1); -+ DUK_CBOR_ASSERT(top >= count); -+ -+ for (;;) { -+ /* First round: compute total size. -+ * Second round: copy into place. -+ */ -+ for (idx = base; idx < top; idx++) { -+ duk_uint8_t *buf_data; -+ duk_size_t buf_size; -+ -+ buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->ctx, idx, &buf_size); -+ if (p != NULL) { -+ if (buf_size > 0U) { -+ (void) memcpy((void *) p, (const void *) buf_data, buf_size); -+ } -+ p += buf_size; -+ } else { -+ total_size += buf_size; -+ if (DUK_CBOR_UNLIKELY(total_size < buf_size)) { /* Wrap check. */ -+ duk__cbor_decode_error(dec_ctx); -+ } -+ } -+ } -+ -+ if (p != NULL) { -+ break; -+ } else { -+ p = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->ctx, total_size); -+ DUK_CBOR_ASSERT(p != NULL); -+ } -+ } -+ -+ duk_replace(dec_ctx->ctx, base); -+ duk_pop_n(dec_ctx->ctx, count - 1); -+} -+ -+static void duk__cbor_decode_and_join_strbuf(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) { -+ duk_idx_t count = 0; -+ for (;;) { -+ if (duk__cbor_decode_checkbreak(dec_ctx)) { -+ break; -+ } -+ duk_require_stack(dec_ctx->ctx, 1); -+ duk__cbor_decode_buffer(dec_ctx, expected_base); -+ count++; -+ if (DUK_UNLIKELY(count <= 0)) { /* Wrap check. */ -+ duk__cbor_decode_error(dec_ctx); -+ } -+ } -+ if (count == 0) { -+ (void) duk_push_fixed_buffer(dec_ctx->ctx, 0); -+ } else if (count > 1) { -+ duk__cbor_decode_join_buffers(dec_ctx, count); -+ } -+} -+ -+static duk_double_t duk__cbor_decode_half_float(duk_cbor_decode_context *dec_ctx) { -+ duk_cbor_dblunion u; -+ const duk_uint8_t *inp; -+ duk_int_t exp; -+ duk_uint_t u16; -+ duk_uint_t tmp; -+ duk_double_t res; -+ -+ inp = duk__cbor_decode_consume(dec_ctx, 2); -+ u16 = ((duk_uint_t) inp[0] << 8) + (duk_uint_t) inp[1]; -+ exp = (duk_int_t) ((u16 >> 10) & 0x1fU) - 15; -+ -+ /* Reconstruct IEEE double into little endian order first, then convert -+ * to host order. -+ */ -+ -+ memset((void *) &u, 0, sizeof(u)); -+ -+ if (exp == -15) { -+ /* Zero or denormal; but note that half float -+ * denormals become double normals. -+ */ -+ if ((u16 & 0x03ffU) == 0) { -+ u.x[7] = inp[0] & 0x80U; -+ } else { -+ /* Create denormal by first creating a double that -+ * contains the denormal bits and a leading implicit -+ * 1-bit. Then subtract away the implicit 1-bit. -+ * -+ * 0.mmmmmmmmmm * 2^-14 -+ * 1.mmmmmmmmmm 0.... * 2^-14 -+ * -1.0000000000 0.... * 2^-14 -+ * -+ * Double exponent: -14 + 1023 = 0x3f1 -+ */ -+ u.x[7] = 0x3fU; -+ u.x[6] = 0x10U + (duk_uint8_t) ((u16 >> 6) & 0x0fU); -+ u.x[5] = (duk_uint8_t) ((u16 << 2) & 0xffU); /* Mask is really 0xfcU */ -+ -+ duk__cbor_dblunion_little_to_host(&u); -+ res = u.d - 0.00006103515625; /* 2^(-14) */ -+ if (u16 & 0x8000U) { -+ res = -res; -+ } -+ return res; -+ } -+ } else if (exp == 16) { -+ /* +/- Inf or NaN. */ -+ if ((u16 & 0x03ffU) == 0) { -+ u.x[7] = (inp[0] & 0x80U) + 0x7fU; -+ u.x[6] = 0xf0U; -+ } else { -+ /* Create a 'quiet NaN' with highest -+ * bit set (there are some platforms -+ * where the NaN payload convention is -+ * the opposite). Keep sign. -+ */ -+ u.x[7] = (inp[0] & 0x80U) + 0x7fU; -+ u.x[6] = 0xf8U; -+ } -+ } else { -+ /* Normal. */ -+ tmp = (inp[0] & 0x80U) ? 0x80000000UL : 0UL; -+ tmp += (duk_uint_t) (exp + 1023) << 20; -+ tmp += (duk_uint_t) (inp[0] & 0x03U) << 18; -+ tmp += (duk_uint_t) (inp[1] & 0xffU) << 10; -+ u.x[7] = (tmp >> 24) & 0xffU; -+ u.x[6] = (tmp >> 16) & 0xffU; -+ u.x[5] = (tmp >> 8) & 0xffU; -+ u.x[4] = (tmp >> 0) & 0xffU; -+ } -+ -+ duk__cbor_dblunion_little_to_host(&u); -+ return u.d; -+} -+ -+static void duk__cbor_decode_string(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) { -+ /* If the CBOR string data is not valid UTF-8 it is technically -+ * invalid CBOR. Possible behaviors at least: -+ * -+ * 1. Reject the input, i.e. throw TypeError. -+ * -+ * 2. Accept the input, but sanitize non-UTF-8 data into UTF-8 -+ * using U+FFFD replacements. Also it might make sense to -+ * decode non-BMP codepoints into surrogates for better -+ * ECMAScript compatibility. -+ * -+ * 3. Accept the input as a Duktape string (which are not always -+ * valid UTF-8), but reject any input that would create a -+ * Symbol representation. -+ * -+ * Current behavior is 3. -+ */ -+ -+ if (ai == 0x1fU) { -+ duk_uint8_t *buf_data; -+ duk_size_t buf_size; -+ -+ duk__cbor_decode_and_join_strbuf(dec_ctx, 0x60U); -+ buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->ctx, -1, &buf_size); -+ (void) duk_push_lstring(dec_ctx->ctx, (const char *) buf_data, buf_size); -+ duk_remove(dec_ctx->ctx, -2); -+ } else { -+ duk_uint32_t len; -+ const duk_uint8_t *inp; -+ -+ len = duk__cbor_decode_aival_uint32(dec_ctx, ib); -+ inp = duk__cbor_decode_consume(dec_ctx, len); -+ (void) duk_push_lstring(dec_ctx->ctx, (const char *) inp, (duk_size_t) len); -+ } -+ if (duk_is_symbol(dec_ctx->ctx, -1)) { -+ /* Refuse to create Symbols when decoding. */ -+ duk__cbor_decode_error(dec_ctx); -+ } -+ -+ /* XXX: Here a Duktape API call to convert input -> utf-8 with -+ * replacements would be nice. -+ */ -+} -+ -+static duk_bool_t duk__cbor_decode_array(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) { -+ duk_uint32_t idx, len; -+ -+ duk__cbor_req_stack(dec_ctx); -+ -+ /* Support arrays up to 0xfffffffeU in length. 0xffffffff is -+ * used as an indefinite length marker. -+ */ -+ if (ai == 0x1fU) { -+ len = 0xffffffffUL; -+ } else { -+ len = duk__cbor_decode_aival_uint32(dec_ctx, ib); -+ if (len == 0xffffffffUL) { -+ return 0; -+ } -+ } -+ -+ /* XXX: use bare array? */ -+ duk_push_array(dec_ctx->ctx); -+ for (idx = 0U; ;) { -+ if (len == 0xffffffffUL && duk__cbor_decode_checkbreak(dec_ctx)) { -+ break; -+ } -+ if (idx == len) { -+ if (ai == 0x1fU) { -+ return 0; -+ } -+ break; -+ } -+ duk__cbor_decode_value(dec_ctx); -+ duk_put_prop_index(dec_ctx->ctx, -2, (duk_uarridx_t) idx); -+ idx++; -+ if (idx == 0U) { -+ return 0; /* wrapped */ -+ } -+ } -+ -+ return 1; -+} -+ -+static duk_bool_t duk__cbor_decode_map(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) { -+ duk_uint32_t count; -+ -+ duk__cbor_req_stack(dec_ctx); -+ -+ if (ai == 0x1fU) { -+ count = 0xffffffffUL; -+ } else { -+ count = duk__cbor_decode_aival_uint32(dec_ctx, ib); -+ if (count == 0xffffffffUL) { -+ return 0; -+ } -+ } -+ -+ /* XXX: use bare object? */ -+ duk_push_object(dec_ctx->ctx); -+ for (;;) { -+ if (count == 0xffffffffUL) { -+ if (duk__cbor_decode_checkbreak(dec_ctx)) { -+ break; -+ } -+ } else { -+ if (count == 0UL) { -+ break; -+ } -+ count--; -+ } -+ -+ /* Non-string keys are coerced to strings, -+ * possibly leading to overwriting previous -+ * keys. Last key of a certain coerced name -+ * wins. If key is an object, it will coerce -+ * to '[object Object]' which is consistent -+ * but potentially misleading. One alternative -+ * would be to skip non-string keys. -+ */ -+ duk__cbor_decode_value(dec_ctx); -+ duk__cbor_decode_value(dec_ctx); -+ duk_put_prop(dec_ctx->ctx, -3); -+ } -+ -+ return 1; -+} -+ -+static duk_double_t duk__cbor_decode_float(duk_cbor_decode_context *dec_ctx) { -+ duk_cbor_fltunion u; -+ const duk_uint8_t *inp; -+ inp = duk__cbor_decode_consume(dec_ctx, 4); -+ (void) memcpy((void *) u.x, (const void *) inp, 4); -+ duk__cbor_fltunion_big_to_host(&u); -+ return (duk_double_t) u.f; -+} -+ -+static duk_double_t duk__cbor_decode_double(duk_cbor_decode_context *dec_ctx) { -+ duk_cbor_dblunion u; -+ const duk_uint8_t *inp; -+ inp = duk__cbor_decode_consume(dec_ctx, 8); -+ (void) memcpy((void *) u.x, (const void *) inp, 8); -+ duk__cbor_dblunion_big_to_host(&u); -+ return u.d; -+} -+ -+#if defined(DUK_CBOR_DECODE_FASTPATH) -+#define DUK__CBOR_AI (ib & 0x1fU) -+ -+static void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) { -+ duk_uint8_t ib; -+ -+ /* Any paths potentially recursing back to duk__cbor_decode_value() -+ * must perform a Duktape value stack growth check. Avoid the check -+ * here for simple paths like primitive values. -+ */ -+ -+ reread_initial_byte: -+#if defined(DUK_CBOR_DPRINT) -+ fprintf(stderr, "cbor decode off=%ld len=%ld\n", (long) dec_ctx->off, (long) dec_ctx->len); -+#endif -+ -+ ib = duk__cbor_decode_readbyte(dec_ctx); -+ -+ /* Full initial byte switch, footprint cost over baseline is ~+1kB. */ -+ /* XXX: Force full switch with no range check. */ -+ -+ switch (ib) { -+ case 0x00U: case 0x01U: case 0x02U: case 0x03U: case 0x04U: case 0x05U: case 0x06U: case 0x07U: -+ case 0x08U: case 0x09U: case 0x0aU: case 0x0bU: case 0x0cU: case 0x0dU: case 0x0eU: case 0x0fU: -+ case 0x10U: case 0x11U: case 0x12U: case 0x13U: case 0x14U: case 0x15U: case 0x16U: case 0x17U: -+ duk_push_uint(dec_ctx->ctx, ib); -+ break; -+ case 0x18U: case 0x19U: case 0x1aU: case 0x1bU: -+ duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/); -+ break; -+ case 0x1cU: case 0x1dU: case 0x1eU: case 0x1fU: -+ goto format_error; -+ case 0x20U: case 0x21U: case 0x22U: case 0x23U: case 0x24U: case 0x25U: case 0x26U: case 0x27U: -+ case 0x28U: case 0x29U: case 0x2aU: case 0x2bU: case 0x2cU: case 0x2dU: case 0x2eU: case 0x2fU: -+ case 0x30U: case 0x31U: case 0x32U: case 0x33U: case 0x34U: case 0x35U: case 0x36U: case 0x37U: -+ duk_push_int(dec_ctx->ctx, -((duk_int_t) ((ib - 0x20U) + 1U))); -+ break; -+ case 0x38U: case 0x39U: case 0x3aU: case 0x3bU: -+ duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/); -+ break; -+ case 0x3cU: case 0x3dU: case 0x3eU: case 0x3fU: -+ goto format_error; -+ case 0x40U: case 0x41U: case 0x42U: case 0x43U: case 0x44U: case 0x45U: case 0x46U: case 0x47U: -+ case 0x48U: case 0x49U: case 0x4aU: case 0x4bU: case 0x4cU: case 0x4dU: case 0x4eU: case 0x4fU: -+ case 0x50U: case 0x51U: case 0x52U: case 0x53U: case 0x54U: case 0x55U: case 0x56U: case 0x57U: -+ /* XXX: Avoid rewind, we know the length already. */ -+ DUK_CBOR_ASSERT(dec_ctx->off > 0U); -+ dec_ctx->off--; -+ duk__cbor_decode_buffer(dec_ctx, 0x40U); -+ break; -+ case 0x58U: case 0x59U: case 0x5aU: case 0x5bU: -+ /* XXX: Avoid rewind, decode length inline. */ -+ DUK_CBOR_ASSERT(dec_ctx->off > 0U); -+ dec_ctx->off--; -+ duk__cbor_decode_buffer(dec_ctx, 0x40U); -+ break; -+ case 0x5cU: case 0x5dU: case 0x5eU: -+ goto format_error; -+ case 0x5fU: -+ duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U); -+ break; -+ case 0x60U: case 0x61U: case 0x62U: case 0x63U: case 0x64U: case 0x65U: case 0x66U: case 0x67U: -+ case 0x68U: case 0x69U: case 0x6aU: case 0x6bU: case 0x6cU: case 0x6dU: case 0x6eU: case 0x6fU: -+ case 0x70U: case 0x71U: case 0x72U: case 0x73U: case 0x74U: case 0x75U: case 0x76U: case 0x77U: -+ /* XXX: Avoid double decode of length. */ -+ duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI); -+ break; -+ case 0x78U: case 0x79U: case 0x7aU: case 0x7bU: -+ /* XXX: Avoid double decode of length. */ -+ duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI); -+ break; -+ case 0x7cU: case 0x7dU: case 0x7eU: -+ goto format_error; -+ case 0x7fU: -+ duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI); -+ break; -+ case 0x80U: case 0x81U: case 0x82U: case 0x83U: case 0x84U: case 0x85U: case 0x86U: case 0x87U: -+ case 0x88U: case 0x89U: case 0x8aU: case 0x8bU: case 0x8cU: case 0x8dU: case 0x8eU: case 0x8fU: -+ case 0x90U: case 0x91U: case 0x92U: case 0x93U: case 0x94U: case 0x95U: case 0x96U: case 0x97U: -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) { -+ goto format_error; -+ } -+ break; -+ case 0x98U: case 0x99U: case 0x9aU: case 0x9bU: -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) { -+ goto format_error; -+ } -+ break; -+ case 0x9cU: case 0x9dU: case 0x9eU: -+ goto format_error; -+ case 0x9fU: -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) { -+ goto format_error; -+ } -+ break; -+ case 0xa0U: case 0xa1U: case 0xa2U: case 0xa3U: case 0xa4U: case 0xa5U: case 0xa6U: case 0xa7U: -+ case 0xa8U: case 0xa9U: case 0xaaU: case 0xabU: case 0xacU: case 0xadU: case 0xaeU: case 0xafU: -+ case 0xb0U: case 0xb1U: case 0xb2U: case 0xb3U: case 0xb4U: case 0xb5U: case 0xb6U: case 0xb7U: -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) { -+ goto format_error; -+ } -+ break; -+ case 0xb8U: case 0xb9U: case 0xbaU: case 0xbbU: -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) { -+ goto format_error; -+ } -+ break; -+ case 0xbcU: case 0xbdU: case 0xbeU: -+ goto format_error; -+ case 0xbfU: -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) { -+ goto format_error; -+ } -+ break; -+ case 0xc0U: case 0xc1U: case 0xc2U: case 0xc3U: case 0xc4U: case 0xc5U: case 0xc6U: case 0xc7U: -+ case 0xc8U: case 0xc9U: case 0xcaU: case 0xcbU: case 0xccU: case 0xcdU: case 0xceU: case 0xcfU: -+ case 0xd0U: case 0xd1U: case 0xd2U: case 0xd3U: case 0xd4U: case 0xd5U: case 0xd6U: case 0xd7U: -+ /* Tag 0-23: drop. */ -+ goto reread_initial_byte; -+ case 0xd8U: case 0xd9U: case 0xdaU: case 0xdbU: -+ duk__cbor_decode_skip_aival_int(dec_ctx, ib); -+ goto reread_initial_byte; -+ case 0xdcU: case 0xddU: case 0xdeU: case 0xdfU: -+ goto format_error; -+ case 0xe0U: -+ goto format_error; -+ case 0xe1U: -+ goto format_error; -+ case 0xe2U: -+ goto format_error; -+ case 0xe3U: -+ goto format_error; -+ case 0xe4U: -+ goto format_error; -+ case 0xe5U: -+ goto format_error; -+ case 0xe6U: -+ goto format_error; -+ case 0xe7U: -+ goto format_error; -+ case 0xe8U: -+ goto format_error; -+ case 0xe9U: -+ goto format_error; -+ case 0xeaU: -+ goto format_error; -+ case 0xebU: -+ goto format_error; -+ case 0xecU: -+ goto format_error; -+ case 0xedU: -+ goto format_error; -+ case 0xeeU: -+ goto format_error; -+ case 0xefU: -+ goto format_error; -+ case 0xf0U: -+ goto format_error; -+ case 0xf1U: -+ goto format_error; -+ case 0xf2U: -+ goto format_error; -+ case 0xf3U: -+ goto format_error; -+ case 0xf4U: -+ duk_push_false(dec_ctx->ctx); -+ break; -+ case 0xf5U: -+ duk_push_true(dec_ctx->ctx); -+ break; -+ case 0xf6U: -+ duk_push_null(dec_ctx->ctx); -+ break; -+ case 0xf7U: -+ duk_push_undefined(dec_ctx->ctx); -+ break; -+ case 0xf8U: -+ /* Simple value 32-255, nothing defined yet, so reject. */ -+ goto format_error; -+ case 0xf9U: { -+ duk_double_t d; -+ d = duk__cbor_decode_half_float(dec_ctx); -+ duk_push_number(dec_ctx->ctx, d); -+ break; -+ } -+ case 0xfaU: { -+ duk_double_t d; -+ d = duk__cbor_decode_float(dec_ctx); -+ duk_push_number(dec_ctx->ctx, d); -+ break; -+ } -+ case 0xfbU: { -+ duk_double_t d; -+ d = duk__cbor_decode_double(dec_ctx); -+ duk_push_number(dec_ctx->ctx, d); -+ break; -+ } -+ case 0xfcU: -+ case 0xfdU: -+ case 0xfeU: -+ case 0xffU: -+ goto format_error; -+ } /* end switch */ -+ -+ return; -+ -+ format_error: -+ duk__cbor_decode_error(dec_ctx); -+} -+#else /* DUK_CBOR_DECODE_FASTPATH */ -+static void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) { -+ duk_uint8_t ib, mt, ai; -+ -+ /* Any paths potentially recursing back to duk__cbor_decode_value() -+ * must perform a Duktape value stack growth check. Avoid the check -+ * here for simple paths like primitive values. -+ */ -+ -+ reread_initial_byte: -+#if defined(DUK_CBOR_DPRINT) -+ fprintf(stderr, "cbor decode off=%ld len=%ld\n", (long) dec_ctx->off, (long) dec_ctx->len); -+#endif -+ -+ ib = duk__cbor_decode_readbyte(dec_ctx); -+ mt = ib >> 5U; -+ ai = ib & 0x1fU; -+ -+ /* Additional information in [24,27] = [0x18,0x1b] has relatively -+ * uniform handling for all major types: read 1/2/4/8 additional -+ * bytes. For major type 7 the 1-byte value is a 'simple type', and -+ * 2/4/8-byte values are floats. For other major types the 1/2/4/8 -+ * byte values are integers. The lengths are uniform, but the typing -+ * is not. -+ */ -+ -+ switch (mt) { -+ case 0U: { /* unsigned integer */ -+ duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/); -+ break; -+ } -+ case 1U: { /* negative integer */ -+ duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/); -+ break; -+ } -+ case 2U: { /* byte string */ -+ if (ai == 0x1fU) { -+ duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U); -+ } else { -+ duk__cbor_decode_rewind(dec_ctx, 1U); -+ duk__cbor_decode_buffer(dec_ctx, 0x40U); -+ } -+ break; -+ } -+ case 3U: { /* text string */ -+ duk__cbor_decode_string(dec_ctx, ib, ai); -+ break; -+ } -+ case 4U: { /* array of data items */ -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, ai) == 0)) { -+ goto format_error; -+ } -+ break; -+ } -+ case 5U: { /* map of pairs of data items */ -+ if (DUK_CBOR_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, ai) == 0)) { -+ goto format_error; -+ } -+ break; -+ } -+ case 6U: { /* semantic tagging */ -+ /* Tags are ignored now, re-read initial byte. A tagged -+ * value may itself be tagged (an unlimited number of times) -+ * so keep on peeling away tags. -+ */ -+ duk__cbor_decode_skip_aival_int(dec_ctx, ib); -+ goto reread_initial_byte; -+ } -+ case 7U: { /* floating point numbers, simple data types, break; other */ -+ switch (ai) { -+ case 0x14U: { -+ duk_push_false(dec_ctx->ctx); -+ break; -+ } -+ case 0x15U: { -+ duk_push_true(dec_ctx->ctx); -+ break; -+ } -+ case 0x16U: { -+ duk_push_null(dec_ctx->ctx); -+ break; -+ } -+ case 0x17U: { -+ duk_push_undefined(dec_ctx->ctx); -+ break; -+ } -+ case 0x18U: { /* more simple values (1 byte) */ -+ /* Simple value encoded in additional byte (none -+ * are defined so far). RFC 7049 states that the -+ * follow-up byte must be 32-255 to minimize -+ * confusion. So, a non-shortest encoding like -+ * f815 (= true, shortest encoding f5) must be -+ * rejected. cbor.me tester rejects f815, but -+ * e.g. Python CBOR binding decodes it as true. -+ */ -+ goto format_error; -+ } -+ case 0x19U: { /* half-float (2 bytes) */ -+ duk_double_t d; -+ d = duk__cbor_decode_half_float(dec_ctx); -+ duk_push_number(dec_ctx->ctx, d); -+ break; -+ } -+ case 0x1aU: { /* float (4 bytes) */ -+ duk_double_t d; -+ d = duk__cbor_decode_float(dec_ctx); -+ duk_push_number(dec_ctx->ctx, d); -+ break; -+ } -+ case 0x1bU: { /* double (8 bytes) */ -+ duk_double_t d; -+ d = duk__cbor_decode_double(dec_ctx); -+ duk_push_number(dec_ctx->ctx, d); -+ break; -+ } -+ case 0xffU: /* unexpected break */ -+ default: { -+ goto format_error; -+ } -+ } /* end switch */ -+ break; -+ } -+ default: { -+ goto format_error; /* will never actually occur */ -+ } -+ } /* end switch */ -+ -+ return; -+ -+ format_error: -+ duk__cbor_decode_error(dec_ctx); -+} -+#endif /* DUK_CBOR_DECODE_FASTPATH */ -+ -+/* -+ * Public APIs -+ */ -+ -+static duk_ret_t duk__cbor_encode_binding(duk_context *ctx) { -+ /* Produce an ArrayBuffer by first decoding into a plain buffer which -+ * mimics a Uint8Array and gettings its .buffer property. -+ */ -+ duk_cbor_encode(ctx, -1, 0); -+ duk_get_prop_string(ctx, -1, "buffer"); -+ return 1; -+} -+ -+static duk_ret_t duk__cbor_decode_binding(duk_context *ctx) { -+ /* Lenient: accept any buffer like. */ -+ duk_cbor_decode(ctx, -1, 0); -+ return 1; -+} -+ -+void duk_cbor_init(duk_context *ctx, duk_uint_t flags) { -+ (void) flags; -+ duk_push_global_object(ctx); -+ duk_push_string(ctx, "CBOR"); -+ duk_push_object(ctx); -+ duk_push_string(ctx, "encode"); -+ duk_push_c_function(ctx, duk__cbor_encode_binding, 1); -+ duk_def_prop(ctx, -3, DUK_DEFPROP_ATTR_WC | DUK_DEFPROP_HAVE_VALUE); -+ duk_push_string(ctx, "decode"); -+ duk_push_c_function(ctx, duk__cbor_decode_binding, 1); -+ duk_def_prop(ctx, -3, DUK_DEFPROP_ATTR_WC | DUK_DEFPROP_HAVE_VALUE); -+ duk_def_prop(ctx, -3, DUK_DEFPROP_ATTR_WC | DUK_DEFPROP_HAVE_VALUE); -+ duk_pop(ctx); -+} -+ -+void duk_cbor_encode(duk_context *ctx, duk_idx_t idx, duk_uint_t encode_flags) { -+ duk_cbor_encode_context enc_ctx; -+ duk_uint8_t *buf; -+ -+ (void) encode_flags; -+ -+ idx = duk_require_normalize_index(ctx, idx); -+ -+ enc_ctx.ctx = ctx; -+ enc_ctx.idx_buf = duk_get_top(ctx); -+ -+ enc_ctx.len = 64; -+ buf = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, enc_ctx.len); -+ enc_ctx.ptr = buf; -+ enc_ctx.buf = buf; -+ enc_ctx.buf_end = buf + enc_ctx.len; -+ -+ duk_dup(ctx, idx); -+ duk__cbor_encode_value(&enc_ctx); -+ duk_resize_buffer(enc_ctx.ctx, enc_ctx.idx_buf, (duk_size_t) (enc_ctx.ptr - enc_ctx.buf)); -+ duk_replace(ctx, idx); -+} -+ -+void duk_cbor_decode(duk_context *ctx, duk_idx_t idx, duk_uint_t decode_flags) { -+ duk_cbor_decode_context dec_ctx; -+ -+ (void) decode_flags; -+ -+ /* Suppress compile warnings for functions only needed with e.g. -+ * asserts enabled. -+ */ -+ (void) duk__cbor_get_reserve; -+ (void) duk__cbor_isinf; -+ (void) duk__cbor_fpclassify; -+ -+ idx = duk_require_normalize_index(ctx, idx); -+ -+ dec_ctx.ctx = ctx; -+ dec_ctx.buf = (const duk_uint8_t *) duk_require_buffer_data(ctx, idx, &dec_ctx.len); -+ dec_ctx.off = 0; -+ /* dec_ctx.len: set above */ -+ -+ duk__cbor_req_stack(&dec_ctx); -+ duk__cbor_decode_value(&dec_ctx); -+ if (dec_ctx.off != dec_ctx.len) { -+ (void) duk_type_error(ctx, "trailing garbage"); -+ } -+ -+ duk_replace(ctx, idx); -+} -diff --git a/dist/source/extras/cbor/duk_cbor.h b/dist/source/extras/cbor/duk_cbor.h -new file mode 100644 -index 0000000..659bd90 ---- /dev/null -+++ b/dist/source/extras/cbor/duk_cbor.h -@@ -0,0 +1,20 @@ -+#if !defined(DUK_CBOR_H_INCLUDED) -+#define DUK_CBOR_H_INCLUDED -+ -+#include "duktape.h" -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+/* No flags at present. */ -+ -+extern void duk_cbor_init(duk_context *ctx, duk_uint_t flags); -+extern void duk_cbor_encode(duk_context *ctx, duk_idx_t idx, duk_uint_t encode_flags); -+extern void duk_cbor_decode(duk_context *ctx, duk_idx_t idx, duk_uint_t decode_flags); -+ -+#if defined(__cplusplus) -+} -+#endif /* end 'extern "C"' wrapper */ -+ -+#endif /* DUK_CBOR_H_INCLUDED */ -diff --git a/dist/source/extras/cbor/jsoncbor.c b/dist/source/extras/cbor/jsoncbor.c -new file mode 100644 -index 0000000..e31cf50 ---- /dev/null -+++ b/dist/source/extras/cbor/jsoncbor.c -@@ -0,0 +1,207 @@ -+#include -+#include "duktape.h" -+#include "duk_cbor.h" -+ -+#define FMT_CBOR 1 -+#define FMT_JSON 2 -+#define FMT_JX 3 -+#define FMT_JS 4 -+ -+static int read_format = 0; -+static int write_format = 0; -+static int write_indent = 0; -+ -+static void push_stdin(duk_context *ctx, int to_string) { -+ unsigned char *buf; -+ size_t off; -+ size_t len; -+ size_t got; -+ -+ off = 0; -+ len = 256; -+ buf = (unsigned char *) duk_push_dynamic_buffer(ctx, len); -+ -+ for (;;) { -+#if 0 -+ fprintf(stderr, "reading %ld of input\n", (long) (len - off)); -+#endif -+ got = fread(buf + off, 1, len - off, stdin); -+ if (got == 0U) { -+ break; -+ } -+ off += got; -+ if (len - off < 256U) { -+ size_t newlen = len * 2U; -+ buf = (unsigned char *) duk_resize_buffer(ctx, -1, newlen); -+ len = newlen; -+ } -+ } -+ buf = (unsigned char *) duk_resize_buffer(ctx, -1, off); -+ -+ if (to_string) { -+ duk_push_lstring(ctx, (const char *) buf, off); -+ duk_remove(ctx, -2); -+ } -+} -+ -+static void usage_and_exit(void) { -+ fprintf(stderr, "Usage: jsoncbor -r cbor|json|jx|js -w cbor|json|jx [--indent N]\n" -+ " jsoncbor -e # shorthand for -r json -w cbor\n" -+ " jsoncbor -d [--indent N] # shorthand for -r cbor -w json [--indent N]\n" -+ "\n" -+ " Input is read from stdin, output is written to stdout.\n" -+ " 'jx' is a Duktape custom JSON extension.\n" -+ " 'js' means evaluate input as an ECMAScript expression.\n"); -+ exit(1); -+} -+ -+static duk_ret_t transcode_helper(duk_context *ctx, void *udata) { -+ const unsigned char *buf; -+ size_t len; -+ duk_idx_t top; -+ -+ (void) udata; -+ -+ /* For Duktape->JSON conversion map all typed arrays into base-64. -+ * This is generally more useful than the default behavior. However, -+ * the base-64 value doesn't have any kind of 'tag' to allow it to be -+ * parsed back into binary automatically. Right now the CBOR parser -+ * creates plain fixed buffers from incoming binary strings. -+ */ -+ duk_eval_string_noresult(ctx, -+ "(function () {\n" -+ " Object.getPrototypeOf(new Uint8Array(0)).toJSON = function () {\n" -+ " return Duktape.enc('base64', this);\n" -+ " };\n" -+ "}())\n"); -+ -+ top = duk_get_top(ctx); -+ -+ if (read_format == FMT_CBOR) { -+ push_stdin(ctx, 0 /*to_string*/); -+ duk_cbor_decode(ctx, -1, 0); -+ } else if (read_format == FMT_JSON) { -+ push_stdin(ctx, 1 /*to_string*/); -+ duk_json_decode(ctx, -1); -+ } else if (read_format == FMT_JX) { -+ duk_eval_string(ctx, "(function(v){return Duktape.dec('jx',v)})"); -+ push_stdin(ctx, 1 /*to_string*/); -+ duk_call(ctx, 1); -+ } else if (read_format == FMT_JS) { -+ push_stdin(ctx, 1 /*to_string*/); -+ duk_eval(ctx); -+ } else { -+ (void) duk_type_error(ctx, "invalid read format"); -+ } -+ -+ if (duk_get_top(ctx) != top + 1) { -+ fprintf(stderr, "top invalid after decoding: %d vs. %d\n", duk_get_top(ctx), top + 1); -+ exit(1); -+ } -+ -+ if (write_format == FMT_CBOR) { -+ duk_cbor_encode(ctx, -1, 0); -+ } else if (write_format == FMT_JSON) { -+ duk_eval_string(ctx, "(function(v,i){return JSON.stringify(v,null,i)})"); -+ duk_insert(ctx, -2); -+ duk_push_int(ctx, write_indent); -+ duk_call(ctx, 2); -+ } else if (write_format == FMT_JX) { -+ duk_eval_string(ctx, "(function(v,i){return Duktape.enc('jx',v,null,i)})"); -+ duk_insert(ctx, -2); -+ duk_push_int(ctx, write_indent); -+ duk_call(ctx, 2); -+ } else { -+ (void) duk_type_error(ctx, "invalid write format"); -+ } -+ -+ if (duk_is_string(ctx, -1)) { -+ buf = (const unsigned char *) duk_require_lstring(ctx, -1, &len); -+ fwrite((const void *) buf, 1, len, stdout); -+ fprintf(stdout, "\n"); -+ } else { -+ buf = (const unsigned char *) duk_require_buffer_data(ctx, -1, &len); -+ fwrite((const void *) buf, 1, len, stdout); -+ } -+ -+ if (duk_get_top(ctx) != top + 1) { -+ fprintf(stderr, "top invalid after encoding: %d vs. %d\n", duk_get_top(ctx), top + 1); -+ exit(1); -+ } -+ -+ return 0; -+} -+ -+static int parse_format(const char *s) { -+ if (strcmp(s, "cbor") == 0) { -+ return FMT_CBOR; -+ } else if (strcmp(s, "json") == 0) { -+ return FMT_JSON; -+ } else if (strcmp(s, "jx") == 0) { -+ return FMT_JX; -+ } else if (strcmp(s, "js") == 0) { -+ return FMT_JS; -+ } else { -+ return 0; -+ } -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ duk_int_t rc; -+ int exitcode = 0; -+ int i; -+ -+ for (i = 1; i < argc; i++) { -+ if (strcmp(argv[i], "-e") == 0) { -+ read_format = FMT_JSON; -+ write_format = FMT_CBOR; -+ } else if (strcmp(argv[i], "-d") == 0) { -+ read_format = FMT_CBOR; -+ write_format = FMT_JSON; -+ } else if (strcmp(argv[i], "-r") == 0) { -+ if (i + 1 >= argc) { -+ goto usage; -+ } -+ read_format = parse_format(argv[i + 1]); -+ i++; -+ } else if (strcmp(argv[i], "-w") == 0) { -+ if (i + 1 >= argc) { -+ goto usage; -+ } -+ write_format = parse_format(argv[i + 1]); -+ i++; -+ } else if (strcmp(argv[i], "--indent") == 0) { -+ if (i + 1 >= argc) { -+ goto usage; -+ } -+ write_indent = atoi(argv[i + 1]); -+ i++; -+ } else { -+ goto usage; -+ } -+ } -+ -+ if (read_format == 0 || write_format == 0) { -+ goto usage; -+ } -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { -+ return 1; -+ } -+ -+ rc = duk_safe_call(ctx, transcode_helper, NULL, 0, 1); -+ if (rc != 0) { -+ fprintf(stderr, "%s\n", duk_safe_to_string(ctx, -1)); -+ exitcode = 1; -+ } -+ /* duk_pop(ctx): unnecessary */ -+ -+ duk_destroy_heap(ctx); -+ -+ return exitcode; -+ -+ usage: -+ usage_and_exit(); -+} -diff --git a/dist/source/extras/cbor/run_testvectors.js b/dist/source/extras/cbor/run_testvectors.js -new file mode 100644 -index 0000000..f3f4f59 ---- /dev/null -+++ b/dist/source/extras/cbor/run_testvectors.js -@@ -0,0 +1,30 @@ -+var testvectors = JSON.parse(new TextDecoder().decode(readFile('appendix_a.json'))); -+ -+// Very rudimentary for now, just dump useful information about decode -+// results and (simple, unstructured) comparison to expected. This is -+// only useful for manually inspecting the results right now. -+ -+testvectors.forEach(function (test, idx) { -+ print('===', idx, '->', Duktape.enc('jx', test)); -+ -+ var cbor = Duktape.dec('base64', test.cbor); -+ try { -+ var dec = CBOR.decode(cbor); -+ } catch (e) { -+ print('decode failed: ' + e); -+ return; -+ } -+ -+ print('dec (jx): ' + Duktape.enc('jx', dec)); -+ -+ if (dec !== test.decoded) { -+ print('decoded compare failed'); -+ } -+ if (test.roundtrip) { -+ var enc = CBOR.encode(dec); -+ print('re-enc: ' + Duktape.enc('hex', enc)); -+ if (Duktape.enc('base64', cbor) !== Duktape.enc('base64', enc)) { -+ print('roundtrip failed'); -+ } -+ } -+}); -diff --git a/dist/source/extras/console/Makefile b/dist/source/extras/console/Makefile -new file mode 100644 -index 0000000..cfd9ecf ---- /dev/null -+++ b/dist/source/extras/console/Makefile -@@ -0,0 +1,20 @@ -+# For manual testing; say 'make' in extras/console and run ./test. -+ -+CC = gcc -+ -+.PHONY: test -+test: -+ -rm -rf ./prep -+ python2 ../../tools/configure.py --quiet --output-directory ./prep -+ $(CC) -std=c99 -Wall -Wextra -o $@ -I./prep -I. ./prep/duktape.c duk_console.c test.c -lm -+ ./test 'console.assert(true, "not shown");' -+ ./test 'console.assert(false, "shown", { foo: 123 });' -+ ./test 'console.log(1, 2, 3, { foo: "bar" });' -+ ./test 'a={}; b={}; a.ref=b; console.log(a,b); b.ref=a; console.log(a,b)' # circular ref -+ ./test 'console.trace(1, 2, 3)' -+ ./test 'console.dir({ foo: 123, bar: [ "foo", "bar" ]});' -+ -+.PHONY: clean -+clean: -+ -rm -rf ./prep -+ -rm -f test -diff --git a/dist/source/extras/console/README.rst b/dist/source/extras/console/README.rst -new file mode 100644 -index 0000000..e81b193 ---- /dev/null -+++ b/dist/source/extras/console/README.rst -@@ -0,0 +1,35 @@ -+========================= -+Minimal 'console' binding -+========================= -+ -+Duktape doesn't provide a ``console`` binding (for example ``console.log``) -+by default because it would be a portability issue for some targets. Instead, -+an application should provide its own ``console`` binding. This directory -+contains an example binding: -+ -+* Add ``duk_console.c`` to list of C sources to compile. -+ -+* Ensure ``duk_console.h`` is in the include path. -+ -+* Include the extra header in calling code and initialize the bindings:: -+ -+ #include "duktape.h" -+ #include "duk_console.h" -+ -+ /* After initializing the Duktape heap or when creating a new -+ * thread with a new global environment: -+ */ -+ duk_console_init(ctx, 0 /*flags*/); -+ -+ Use the ``DUK_CONSOLE_PROXY_WRAPPER`` to enable a Proxy wrapper for the -+ console object. The wrapper allows all undefined methods (for example, -+ ``console.foo``) to be handled as no-ops instead of throwing an error. -+ See ``duk_console.h`` for full flags list. -+ -+* After these steps, ``console`` will be registered to the global object -+ and is ready to use. -+ -+* By default the console object will use ``stdout`` for log levels up to -+ info, and ``stderr`` for warning and above. You can change this by -+ providing either ``DUK_CONSOLE_STDOUT_ONLY`` or ``DUK_CONSOLE_STDERR_ONLY`` -+ in ``duk_console_init()`` flags. -diff --git a/dist/source/extras/console/duk_console.c b/dist/source/extras/console/duk_console.c -new file mode 100644 -index 0000000..70ff6f0 ---- /dev/null -+++ b/dist/source/extras/console/duk_console.c -@@ -0,0 +1,185 @@ -+/* -+ * Minimal 'console' binding. -+ * -+ * https://github.com/DeveloperToolsWG/console-object/blob/master/api.md -+ * https://developers.google.com/web/tools/chrome-devtools/debug/console/console-reference -+ * https://developer.mozilla.org/en/docs/Web/API/console -+ */ -+ -+#include -+#include -+#include "duktape.h" -+#include "duk_console.h" -+ -+/* XXX: Add some form of log level filtering. */ -+ -+/* XXX: Should all output be written via e.g. console.write(formattedMsg)? -+ * This would make it easier for user code to redirect all console output -+ * to a custom backend. -+ */ -+ -+/* XXX: Init console object using duk_def_prop() when that call is available. */ -+ -+static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) { -+ duk_uint_t flags = (duk_uint_t) duk_get_current_magic(ctx); -+ FILE *output = (flags & DUK_CONSOLE_STDOUT_ONLY) ? stdout : stderr; -+ duk_idx_t n = duk_get_top(ctx); -+ duk_idx_t i; -+ -+ duk_get_global_string(ctx, "console"); -+ duk_get_prop_string(ctx, -1, "format"); -+ -+ for (i = 0; i < n; i++) { -+ if (duk_check_type_mask(ctx, i, DUK_TYPE_MASK_OBJECT)) { -+ /* Slow path formatting. */ -+ duk_dup(ctx, -1); /* console.format */ -+ duk_dup(ctx, i); -+ duk_call(ctx, 1); -+ duk_replace(ctx, i); /* arg[i] = console.format(arg[i]); */ -+ } -+ } -+ -+ duk_pop_2(ctx); -+ -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, n); -+ -+ if (error_name) { -+ duk_push_error_object(ctx, DUK_ERR_ERROR, "%s", duk_require_string(ctx, -1)); -+ duk_push_string(ctx, "name"); -+ duk_push_string(ctx, error_name); -+ duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE); /* to get e.g. 'Trace: 1 2 3' */ -+ duk_get_prop_string(ctx, -1, "stack"); -+ } -+ -+ fprintf(output, "%s\n", duk_to_string(ctx, -1)); -+ if (flags & DUK_CONSOLE_FLUSH) { -+ fflush(output); -+ } -+ return 0; -+} -+ -+static duk_ret_t duk__console_assert(duk_context *ctx) { -+ if (duk_to_boolean(ctx, 0)) { -+ return 0; -+ } -+ duk_remove(ctx, 0); -+ -+ return duk__console_log_helper(ctx, "AssertionError"); -+} -+ -+static duk_ret_t duk__console_log(duk_context *ctx) { -+ return duk__console_log_helper(ctx, NULL); -+} -+ -+static duk_ret_t duk__console_trace(duk_context *ctx) { -+ return duk__console_log_helper(ctx, "Trace"); -+} -+ -+static duk_ret_t duk__console_info(duk_context *ctx) { -+ return duk__console_log_helper(ctx, NULL); -+} -+ -+static duk_ret_t duk__console_warn(duk_context *ctx) { -+ return duk__console_log_helper(ctx, NULL); -+} -+ -+static duk_ret_t duk__console_error(duk_context *ctx) { -+ return duk__console_log_helper(ctx, "Error"); -+} -+ -+static duk_ret_t duk__console_dir(duk_context *ctx) { -+ /* For now, just share the formatting of .log() */ -+ return duk__console_log_helper(ctx, 0); -+} -+ -+static void duk__console_reg_vararg_func(duk_context *ctx, duk_c_function func, const char *name, duk_uint_t flags) { -+ duk_push_c_function(ctx, func, DUK_VARARGS); -+ duk_push_string(ctx, "name"); -+ duk_push_string(ctx, name); -+ duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE); /* Improve stacktraces by displaying function name */ -+ duk_set_magic(ctx, -1, (duk_int_t) flags); -+ duk_put_prop_string(ctx, -2, name); -+} -+ -+void duk_console_init(duk_context *ctx, duk_uint_t flags) { -+ duk_uint_t flags_orig; -+ -+ /* If both DUK_CONSOLE_STDOUT_ONLY and DUK_CONSOLE_STDERR_ONLY where specified, -+ * just turn off DUK_CONSOLE_STDOUT_ONLY and keep DUK_CONSOLE_STDERR_ONLY. -+ */ -+ if ((flags & DUK_CONSOLE_STDOUT_ONLY) && (flags & DUK_CONSOLE_STDERR_ONLY)) { -+ flags &= ~DUK_CONSOLE_STDOUT_ONLY; -+ } -+ /* Remember the (possibly corrected) flags we received. */ -+ flags_orig = flags; -+ -+ duk_push_object(ctx); -+ -+ /* Custom function to format objects; user can replace. -+ * For now, try JX-formatting and if that fails, fall back -+ * to ToString(v). -+ */ -+ duk_eval_string(ctx, -+ "(function (E) {" -+ "return function format(v){" -+ "try{" -+ "return E('jx',v);" -+ "}catch(e){" -+ "return String(v);" /* String() allows symbols, ToString() internal algorithm doesn't. */ -+ "}" -+ "};" -+ "})(Duktape.enc)"); -+ duk_put_prop_string(ctx, -2, "format"); -+ -+ flags = flags_orig; -+ if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) { -+ /* No output indicators were specified; these levels go to stdout. */ -+ flags |= DUK_CONSOLE_STDOUT_ONLY; -+ } -+ duk__console_reg_vararg_func(ctx, duk__console_assert, "assert", flags); -+ duk__console_reg_vararg_func(ctx, duk__console_log, "log", flags); -+ duk__console_reg_vararg_func(ctx, duk__console_log, "debug", flags); /* alias to console.log */ -+ duk__console_reg_vararg_func(ctx, duk__console_trace, "trace", flags); -+ duk__console_reg_vararg_func(ctx, duk__console_info, "info", flags); -+ -+ flags = flags_orig; -+ if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) { -+ /* No output indicators were specified; these levels go to stderr. */ -+ flags |= DUK_CONSOLE_STDERR_ONLY; -+ } -+ duk__console_reg_vararg_func(ctx, duk__console_warn, "warn", flags); -+ duk__console_reg_vararg_func(ctx, duk__console_error, "error", flags); -+ duk__console_reg_vararg_func(ctx, duk__console_error, "exception", flags); /* alias to console.error */ -+ duk__console_reg_vararg_func(ctx, duk__console_dir, "dir", flags); -+ -+ duk_put_global_string(ctx, "console"); -+ -+ /* Proxy wrapping: ensures any undefined console method calls are -+ * ignored silently. This was required specifically by the -+ * DeveloperToolsWG proposal (and was implemented also by Firefox: -+ * https://bugzilla.mozilla.org/show_bug.cgi?id=629607). This is -+ * apparently no longer the preferred way of implementing console. -+ * When Proxy is enabled, whitelist at least .toJSON() to avoid -+ * confusing JX serialization of the console object. -+ */ -+ -+ if (flags & DUK_CONSOLE_PROXY_WRAPPER) { -+ /* Tolerate failure to initialize Proxy wrapper in case -+ * Proxy support is disabled. -+ */ -+ (void) duk_peval_string_noresult(ctx, -+ "(function(){" -+ "var D=function(){};" -+ "var W={toJSON:true};" /* whitelisted */ -+ "console=new Proxy(console,{" -+ "get:function(t,k){" -+ "var v=t[k];" -+ "return typeof v==='function'||W[k]?v:D;" -+ "}" -+ "});" -+ "})();" -+ ); -+ } -+} -diff --git a/dist/source/extras/console/duk_console.h b/dist/source/extras/console/duk_console.h -new file mode 100644 -index 0000000..d341e22 ---- /dev/null -+++ b/dist/source/extras/console/duk_console.h -@@ -0,0 +1,29 @@ -+#if !defined(DUK_CONSOLE_H_INCLUDED) -+#define DUK_CONSOLE_H_INCLUDED -+ -+#include "duktape.h" -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+/* Use a proxy wrapper to make undefined methods (console.foo()) no-ops. */ -+#define DUK_CONSOLE_PROXY_WRAPPER (1U << 0) -+ -+/* Flush output after every call. */ -+#define DUK_CONSOLE_FLUSH (1U << 1) -+ -+/* Send output to stdout only (default is mixed stdout/stderr). */ -+#define DUK_CONSOLE_STDOUT_ONLY (1U << 2) -+ -+/* Send output to stderr only (default is mixed stdout/stderr). */ -+#define DUK_CONSOLE_STDERR_ONLY (1U << 3) -+ -+/* Initialize the console system */ -+extern void duk_console_init(duk_context *ctx, duk_uint_t flags); -+ -+#if defined(__cplusplus) -+} -+#endif /* end 'extern "C"' wrapper */ -+ -+#endif /* DUK_CONSOLE_H_INCLUDED */ -diff --git a/dist/source/extras/console/test.c b/dist/source/extras/console/test.c -new file mode 100644 -index 0000000..9dc8183 ---- /dev/null -+++ b/dist/source/extras/console/test.c -@@ -0,0 +1,30 @@ -+#include -+#include "duktape.h" -+#include "duk_console.h" -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ int i; -+ int exitcode = 0; -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { -+ return 1; -+ } -+ -+ duk_console_init(ctx, DUK_CONSOLE_PROXY_WRAPPER /*flags*/); -+ printf("top after init: %ld\n", (long) duk_get_top(ctx)); -+ -+ for (i = 1; i < argc; i++) { -+ printf("Evaling: %s\n", argv[i]); -+ if (duk_peval_string(ctx, argv[i]) != 0) { -+ exitcode = 1; -+ } -+ printf("--> %s\n", duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ } -+ -+ printf("Done\n"); -+ duk_destroy_heap(ctx); -+ return exitcode; -+} -diff --git a/dist/source/extras/duk-v1-compat/Makefile b/dist/source/extras/duk-v1-compat/Makefile -new file mode 100644 -index 0000000..96bb313 ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/Makefile -@@ -0,0 +1,15 @@ -+# For manual testing; say 'make' in extras/duk-v1-compat and run ./test. -+ -+CC = gcc -+ -+.PHONY: test -+test: -+ -rm -rf ./prep -+ python2 ../../tools/configure.py --quiet --output-directory ./prep -+ $(CC) -std=c99 -Wall -Wextra -o $@ -I./prep -I. ./prep/duktape.c duk_v1_compat.c test.c -lm -+ ./test -+ -+.PHONY: clean -+clean: -+ -rm -rf ./prep -+ -rm -f test -diff --git a/dist/source/extras/duk-v1-compat/README.rst b/dist/source/extras/duk-v1-compat/README.rst -new file mode 100644 -index 0000000..5b0d7d5 ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/README.rst -@@ -0,0 +1,25 @@ -+================================ -+Duktape V1 compatibility helpers -+================================ -+ -+Provides helpers for migrating from Duktape 1.x to 2.x: -+ -+* Add ``duk_v1_compat.c`` to list of C sources to compile. -+ -+* Ensure ``duk_v1_compat.h`` is in the include path. -+ -+* Include the extra header in calling code:: -+ -+ #include "duktape.h" -+ #include "duk_v1_compat.h" -+ -+ /* ... */ -+ -+ duk_dump_context_stdout(ctx); /* Removed in Duktape 2.x. */ -+ -+The helpers don't restore full 1.x compatibility because some API calls such -+as ``duk_safe_call()`` have changed in an incompatible manner. -+ -+The old APIs are documented in: -+ -+* http://duktape.org/1.5.0/api.html -diff --git a/dist/source/extras/duk-v1-compat/duk_v1_compat.c b/dist/source/extras/duk-v1-compat/duk_v1_compat.c -new file mode 100644 -index 0000000..e4a44db ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/duk_v1_compat.c -@@ -0,0 +1,131 @@ -+#include -+#include "duktape.h" -+#include "duk_v1_compat.h" -+ -+/* -+ * duk_dump_context_{stdout,stderr}() -+ */ -+ -+void duk_dump_context_stdout(duk_context *ctx) { -+ duk_push_context_dump(ctx); -+ fprintf(stdout, "%s\n", duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+} -+ -+void duk_dump_context_stderr(duk_context *ctx) { -+ duk_push_context_dump(ctx); -+ fprintf(stderr, "%s\n", duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+} -+ -+/* -+ * duk_push_string_file() and duk_push_string_file_raw() -+ */ -+ -+const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) { -+ FILE *f = NULL; -+ char *buf; -+ long sz; /* ANSI C typing */ -+ -+ if (!path) { -+ goto fail; -+ } -+ f = fopen(path, "rb"); -+ if (!f) { -+ goto fail; -+ } -+ if (fseek(f, 0, SEEK_END) < 0) { -+ goto fail; -+ } -+ sz = ftell(f); -+ if (sz < 0) { -+ goto fail; -+ } -+ if (fseek(f, 0, SEEK_SET) < 0) { -+ goto fail; -+ } -+ buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz); -+ if ((size_t) fread(buf, 1, (size_t) sz, f) != (size_t) sz) { -+ duk_pop(ctx); -+ goto fail; -+ } -+ (void) fclose(f); /* ignore fclose() error */ -+ return duk_buffer_to_string(ctx, -1); -+ -+ fail: -+ if (f) { -+ (void) fclose(f); /* ignore fclose() error */ -+ } -+ -+ if (flags & DUK_STRING_PUSH_SAFE) { -+ duk_push_undefined(ctx); -+ } else { -+ (void) duk_type_error(ctx, "read file error"); -+ } -+ return NULL; -+} -+ -+/* -+ * duk_eval_file(), duk_compile_file(), and their variants -+ */ -+ -+void duk_eval_file(duk_context *ctx, const char *path) { -+ duk_push_string_file_raw(ctx, path, 0); -+ duk_push_string(ctx, path); -+ duk_compile(ctx, DUK_COMPILE_EVAL); -+ duk_push_global_object(ctx); /* 'this' binding */ -+ duk_call_method(ctx, 0); -+} -+ -+void duk_eval_file_noresult(duk_context *ctx, const char *path) { -+ duk_eval_file(ctx, path); -+ duk_pop(ctx); -+} -+ -+duk_int_t duk_peval_file(duk_context *ctx, const char *path) { -+ duk_int_t rc; -+ -+ duk_push_string_file_raw(ctx, path, DUK_STRING_PUSH_SAFE); -+ duk_push_string(ctx, path); -+ rc = duk_pcompile(ctx, DUK_COMPILE_EVAL); -+ if (rc != 0) { -+ return rc; -+ } -+ duk_push_global_object(ctx); /* 'this' binding */ -+ rc = duk_pcall_method(ctx, 0); -+ return rc; -+} -+ -+duk_int_t duk_peval_file_noresult(duk_context *ctx, const char *path) { -+ duk_int_t rc; -+ -+ rc = duk_peval_file(ctx, path); -+ duk_pop(ctx); -+ return rc; -+} -+ -+void duk_compile_file(duk_context *ctx, duk_uint_t flags, const char *path) { -+ duk_push_string_file_raw(ctx, path, 0); -+ duk_push_string(ctx, path); -+ duk_compile(ctx, flags); -+} -+ -+duk_int_t duk_pcompile_file(duk_context *ctx, duk_uint_t flags, const char *path) { -+ duk_int_t rc; -+ -+ duk_push_string_file_raw(ctx, path, DUK_STRING_PUSH_SAFE); -+ duk_push_string(ctx, path); -+ rc = duk_pcompile(ctx, flags); -+ return rc; -+} -+ -+/* -+ * duk_to_defaultvalue() -+ */ -+ -+void duk_to_defaultvalue(duk_context *ctx, duk_idx_t idx, duk_int_t hint) { -+ duk_require_type_mask(ctx, idx, DUK_TYPE_MASK_OBJECT | -+ DUK_TYPE_MASK_BUFFER | -+ DUK_TYPE_MASK_LIGHTFUNC); -+ duk_to_primitive(ctx, idx, hint); -+} -diff --git a/dist/source/extras/duk-v1-compat/duk_v1_compat.h b/dist/source/extras/duk-v1-compat/duk_v1_compat.h -new file mode 100644 -index 0000000..09aa5a9 ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/duk_v1_compat.h -@@ -0,0 +1,36 @@ -+#if !defined(DUK_V1_COMPAT_INCLUDED) -+#define DUK_V1_COMPAT_INCLUDED -+ -+#include "duktape.h" -+ -+#if defined(__cplusplus) -+extern "C" { -+#endif -+ -+/* Straight flag rename */ -+#if !defined(DUK_ENUM_INCLUDE_INTERNAL) -+#define DUK_ENUM_INCLUDE_INTERNAL DUK_ENUM_INCLUDE_HIDDEN -+#endif -+ -+/* Flags for duk_push_string_file_raw() */ -+#define DUK_STRING_PUSH_SAFE (1 << 0) /* no error if file does not exist */ -+ -+extern void duk_dump_context_stdout(duk_context *ctx); -+extern void duk_dump_context_stderr(duk_context *ctx); -+extern const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags); -+extern void duk_eval_file(duk_context *ctx, const char *path); -+extern void duk_eval_file_noresult(duk_context *ctx, const char *path); -+extern duk_int_t duk_peval_file(duk_context *ctx, const char *path); -+extern duk_int_t duk_peval_file_noresult(duk_context *ctx, const char *path); -+extern void duk_compile_file(duk_context *ctx, duk_uint_t flags, const char *path); -+extern duk_int_t duk_pcompile_file(duk_context *ctx, duk_uint_t flags, const char *path); -+extern void duk_to_defaultvalue(duk_context *ctx, duk_idx_t idx, duk_int_t hint); -+ -+#define duk_push_string_file(ctx,path) \ -+ duk_push_string_file_raw((ctx), (path), 0) -+ -+#if defined(__cplusplus) -+} -+#endif /* end 'extern "C"' wrapper */ -+ -+#endif /* DUK_V1_COMPAT_INCLUDED */ -diff --git a/dist/source/extras/duk-v1-compat/test.c b/dist/source/extras/duk-v1-compat/test.c -new file mode 100644 -index 0000000..82e97b4 ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/test.c -@@ -0,0 +1,104 @@ -+#include -+#include "duktape.h" -+#include "duk_v1_compat.h" -+ -+static duk_ret_t my_print(duk_context *ctx) { -+ duk_push_string(ctx, " "); -+ duk_insert(ctx, 0); -+ duk_join(ctx, duk_get_top(ctx) - 1); -+ printf("%s\n", duk_to_string(ctx, -1)); -+ fflush(stdout); -+ return 0; -+} -+ -+int main(int argc, char *argv[]) { -+ duk_context *ctx; -+ int i; -+ duk_int_t rc; -+ -+ ctx = duk_create_heap_default(); -+ if (!ctx) { -+ return 1; -+ } -+ -+ /* Minimal print() provider. */ -+ duk_push_c_function(ctx, my_print, DUK_VARARGS); -+ duk_put_global_string(ctx, "print"); -+ -+ printf("top after init: %ld\n", (long) duk_get_top(ctx)); -+ -+ for (i = 1; i < argc; i++) { -+ printf("Evaling: %s\n", argv[i]); -+ (void) duk_peval_string(ctx, argv[i]); -+ printf("--> %s\n", duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ } -+ -+ /* Test duk_dump_context_{stdout,stderr}() */ -+ -+ duk_push_string(ctx, "dump to stdout"); -+ duk_dump_context_stdout(ctx); -+ duk_pop(ctx); -+ -+ duk_push_string(ctx, "dump to stderr"); -+ duk_dump_context_stderr(ctx); -+ duk_pop(ctx); -+ -+ /* Test duk_eval_file() and related. */ -+ -+ printf("top before duk_eval_file(): %ld\n", (long) duk_get_top(ctx)); -+ duk_eval_file(ctx, "test_eval1.js"); -+ printf("top after duk_eval_file(): %ld\n", (long) duk_get_top(ctx)); -+ printf(" --> %s\n", duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ -+ printf("top before duk_eval_file_noresult(): %ld\n", (long) duk_get_top(ctx)); -+ duk_eval_file_noresult(ctx, "test_eval1.js"); -+ printf("top after duk_eval_file_noresult(): %ld\n", (long) duk_get_top(ctx)); -+ -+ printf("top before duk_peval_file(): %ld\n", (long) duk_get_top(ctx)); -+ rc = duk_peval_file(ctx, "test_eval1.js"); -+ printf("top after duk_peval_file(): %ld\n", (long) duk_get_top(ctx)); -+ printf(" --> %ld, %s\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ -+ printf("top before duk_peval_file(): %ld\n", (long) duk_get_top(ctx)); -+ rc = duk_peval_file(ctx, "test_eval2.js"); -+ printf("top after duk_peval_file(): %ld\n", (long) duk_get_top(ctx)); -+ printf(" --> %ld, %s\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ -+ printf("top before duk_peval_file_noresult(): %ld\n", (long) duk_get_top(ctx)); -+ rc = duk_peval_file_noresult(ctx, "test_eval1.js"); -+ printf("top after duk_peval_file_noresult(): %ld\n", (long) duk_get_top(ctx)); -+ printf(" --> %ld\n", (long) rc); -+ -+ printf("top before duk_peval_file_noresult(): %ld\n", (long) duk_get_top(ctx)); -+ rc = duk_peval_file_noresult(ctx, "test_eval2.js"); -+ printf("top after duk_peval_file_noresult(): %ld\n", (long) duk_get_top(ctx)); -+ printf(" --> %ld\n", (long) rc); -+ -+ /* Test duk_compile_file() and related. */ -+ -+ printf("top before duk_compile_file(): %ld\n", (long) duk_get_top(ctx)); -+ duk_compile_file(ctx, 0, "test_compile1.js"); -+ printf("top after duk_compile_file(): %ld\n", (long) duk_get_top(ctx)); -+ duk_call(ctx, 0); -+ duk_pop(ctx); -+ -+ printf("top before duk_pcompile_file(): %ld\n", (long) duk_get_top(ctx)); -+ rc = duk_pcompile_file(ctx, 0, "test_compile1.js"); -+ printf("top after duk_pcompile_file(): %ld\n", (long) duk_get_top(ctx)); -+ printf(" --> %ld: %s\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ -+ printf("top before duk_pcompile_file(): %ld\n", (long) duk_get_top(ctx)); -+ rc = duk_pcompile_file(ctx, 0, "test_compile2.js"); -+ printf("top after duk_pcompile_file(): %ld\n", (long) duk_get_top(ctx)); -+ printf(" --> %ld: %s\n", (long) rc, duk_safe_to_string(ctx, -1)); -+ duk_pop(ctx); -+ -+ printf("Done\n"); -+ duk_destroy_heap(ctx); -+ return 0; -+} -diff --git a/dist/source/extras/duk-v1-compat/test_compile1.js b/dist/source/extras/duk-v1-compat/test_compile1.js -new file mode 100644 -index 0000000..92ee80c ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/test_compile1.js -@@ -0,0 +1,3 @@ -+// File to compile, no error -+print('Hello from test_compile1.js'); -+print(new Error('test error for traceback (shows filename)').stack); -diff --git a/dist/source/extras/duk-v1-compat/test_compile2.js b/dist/source/extras/duk-v1-compat/test_compile2.js -new file mode 100644 -index 0000000..1cb1ffc ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/test_compile2.js -@@ -0,0 +1,3 @@ -+// File to compile, syntax error -+print('Hello from test_compile2.js'); -+= y +; -diff --git a/dist/source/extras/duk-v1-compat/test_eval1.js b/dist/source/extras/duk-v1-compat/test_eval1.js -new file mode 100644 -index 0000000..e2ee178 ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/test_eval1.js -@@ -0,0 +1,4 @@ -+// File to eval, no error -+print('Hello from test_eval1.js'); -+print(new Error('test error for traceback (shows filename)').stack); -+123; -diff --git a/dist/source/extras/duk-v1-compat/test_eval2.js b/dist/source/extras/duk-v1-compat/test_eval2.js -new file mode 100644 -index 0000000..443eb2c ---- /dev/null -+++ b/dist/source/extras/duk-v1-compat/test_eval2.js -@@ -0,0 +1,4 @@ -+// File to eval, throws error -+print('Hello from test_eval2.js'); -+print(new Error('test error for traceback (shows filename)').stack); -+throw new Error('aiee'); -diff --git a/dist/source/extras/logging/Makefile b/dist/source/extras/logging/Makefile -new file mode 100644 -index 0000000..0eda5a5 ---- /dev/null -+++ b/dist/source/extras/logging/Makefile -@@ -0,0 +1,22 @@ -+# For manual testing; say 'make' in extras/logging and run ./test. -+ -+CC = gcc -+ -+.PHONY: test -+test: -+ -rm -rf ./prep -+ python2 ../../tools/configure.py --quiet --output-directory ./prep -+ $(CC) -std=c99 -Wall -Wextra -otest -I./prep ./prep/duktape.c duk_logging.c test.c -lm -+ ./test 'L = new Duktape.Logger(); L.trace("testing"); L.l = 0; L.trace("testing 2");' -+ ./test 'L = new Duktape.Logger(); L.debug("testing"); L.l = 1; L.debug("testing 2");' -+ ./test 'L = new Duktape.Logger(); L.info("testing");' -+ ./test 'L = new Duktape.Logger(); L.warn("testing");' -+ ./test 'L = new Duktape.Logger(); L.error("testing");' -+ ./test 'L = new Duktape.Logger(); L.fatal("testing");' -+ ./test 'L = new Duktape.Logger(); L.info("testing"); L.n = "loggerName"; L.info("new name");' -+ ./test 'L = new Duktape.Logger("argname"); L.info("testing");' -+ -+.PHONY: clean -+clean: -+ -rm -rf ./prep -+ -rm -f test -diff --git a/dist/source/extras/logging/README.rst b/dist/source/extras/logging/README.rst -new file mode 100644 -index 0000000..eb87481 ---- /dev/null -+++ b/dist/source/extras/logging/README.rst -@@ -0,0 +1,33 @@ -+======================================== -+Duktape 1.x compatible logging framework -+======================================== -+ -+The default ``Duktape.Logger`` object and the logging related C API calls -+(``duk_log()``, ``duk_log_va()``) were removed in Duktape 2.x because they -+depended on stdout/stderr and were thus a portability issue for some targets -+(there were also other issues, such as the logging framework not always -+matching user expectations). This directory contains Duktape 1.x compatible -+``Duktape.Logger`` object and logging API calls: -+ -+* Add ``duk_logging.c`` to list of C sources to compile. -+ -+* Ensure ``duk_logging.h`` is in the include path. -+ -+* Include the extra header in calling code and initialize the bindings:: -+ -+ #include "duktape.h" -+ #include "duk_logging.h" -+ -+ /* After initializing the Duktape heap or when creating a new -+ * thread with a new global environment: -+ */ -+ duk_logging_init(ctx, 0 /*flags*/); -+ -+ See ``duk_logging.h`` for available flags. -+ -+* After these steps, ``Duktape.Logger`` will be registered to the ``Duktape`` -+ object and is ready to use. -+ -+See https://github.com/svaarala/duktape/blob/master/doc/logging.rst and -+http://wiki.duktape.org/HowtoLogging.html for more information on the -+logging framework design and functionality. -diff --git a/dist/source/extras/logging/duk_logging.c b/dist/source/extras/logging/duk_logging.c -new file mode 100644 -index 0000000..1b91d95 ---- /dev/null -+++ b/dist/source/extras/logging/duk_logging.c -@@ -0,0 +1,380 @@ -+/* -+ * Logging support -+ */ -+ -+#include -+#include -+#include -+#include "duktape.h" -+#include "duk_logging.h" -+ -+/* XXX: uses stderr always for now, configurable? */ -+ -+#define DUK_LOGGING_FLUSH /* Duktape 1.x: flush stderr */ -+ -+/* 3-letter log level strings. */ -+static const char duk__log_level_strings[] = { -+ 'T', 'R', 'C', 'D', 'B', 'G', 'I', 'N', 'F', -+ 'W', 'R', 'N', 'E', 'R', 'R', 'F', 'T', 'L' -+}; -+ -+/* Log method names. */ -+static const char *duk__log_method_names[] = { -+ "trace", "debug", "info", "warn", "error", "fatal" -+}; -+ -+/* Constructor. */ -+static duk_ret_t duk__logger_constructor(duk_context *ctx) { -+ duk_idx_t nargs; -+ -+ /* Calling as a non-constructor is not meaningful. */ -+ if (!duk_is_constructor_call(ctx)) { -+ return DUK_RET_TYPE_ERROR; -+ } -+ -+ nargs = duk_get_top(ctx); -+ duk_set_top(ctx, 1); -+ -+ duk_push_this(ctx); -+ -+ /* [ name this ] */ -+ -+ if (nargs == 0) { -+ /* Automatic defaulting of logger name from caller. This -+ * would work poorly with tail calls, but constructor calls -+ * are currently never tail calls, so tail calls are not an -+ * issue now. -+ */ -+ -+ duk_inspect_callstack_entry(ctx, -2); -+ if (duk_is_object(ctx, -1)) { -+ if (duk_get_prop_string(ctx, -1, "function")) { -+ if (duk_get_prop_string(ctx, -1, "fileName")) { -+ if (duk_is_string(ctx, -1)) { -+ duk_replace(ctx, 0); -+ } -+ } -+ } -+ } -+ /* Leave values on stack on purpose, ignored below. */ -+ -+ /* Stripping the filename might be a good idea -+ * ("/foo/bar/quux.js" -> logger name "quux"), -+ * but now used verbatim. -+ */ -+ } -+ /* The stack is unbalanced here on purpose; we only rely on the -+ * initial two values: [ name this ]. -+ */ -+ -+ if (duk_is_string(ctx, 0)) { -+ duk_dup(ctx, 0); -+ duk_put_prop_string(ctx, 1, "n"); -+ } else { -+ /* don't set 'n' at all, inherited value is used as name */ -+ } -+ -+ duk_compact(ctx, 1); -+ -+ return 0; /* keep default instance */ -+} -+ -+/* Default function to format objects. Tries to use toLogString() but falls -+ * back to toString(). Any errors are propagated out without catching. -+ */ -+static duk_ret_t duk__logger_prototype_fmt(duk_context *ctx) { -+ if (duk_get_prop_string(ctx, 0, "toLogString")) { -+ /* [ arg toLogString ] */ -+ -+ duk_dup(ctx, 0); -+ duk_call_method(ctx, 0); -+ -+ /* [ arg result ] */ -+ return 1; -+ } -+ -+ /* [ arg undefined ] */ -+ duk_pop(ctx); -+ duk_to_string(ctx, 0); -+ return 1; -+} -+ -+/* Default function to write a formatted log line. Writes to stderr, -+ * appending a newline to the log line. -+ * -+ * The argument is a buffer; avoid coercing the buffer to a string to -+ * avoid string table traffic. -+ */ -+static duk_ret_t duk__logger_prototype_raw(duk_context *ctx) { -+ const char *data; -+ duk_size_t data_len; -+ -+ data = (const char *) duk_require_buffer_data(ctx, 0, &data_len); -+ fwrite((const void *) data, 1, data_len, stderr); -+ fputc((int) '\n', stderr); -+#if defined(DUK_LOGGING_FLUSH) -+ fflush(stderr); -+#endif -+ return 0; -+} -+ -+/* Log frontend shared helper, magic value indicates log level. Provides -+ * frontend functions: trace(), debug(), info(), warn(), error(), fatal(). -+ * This needs to have small footprint, reasonable performance, minimal -+ * memory churn, etc. -+ */ -+static duk_ret_t duk__logger_prototype_log_shared(duk_context *ctx) { -+ duk_double_t now; -+ duk_time_components comp; -+ duk_small_int_t entry_lev; -+ duk_small_int_t logger_lev; -+ duk_int_t nargs; -+ duk_int_t i; -+ duk_size_t tot_len; -+ const duk_uint8_t *arg_str; -+ duk_size_t arg_len; -+ duk_uint8_t *buf, *p; -+ const duk_uint8_t *q; -+ duk_uint8_t date_buf[32]; /* maximum format length is 24+1 (NUL), round up. */ -+ duk_size_t date_len; -+ duk_small_int_t rc; -+ -+ /* XXX: sanitize to printable (and maybe ASCII) */ -+ /* XXX: better multiline */ -+ -+ /* -+ * Logger arguments are: -+ * -+ * magic: log level (0-5) -+ * this: logger -+ * stack: plain log args -+ * -+ * We want to minimize memory churn so a two-pass approach -+ * is used: first pass formats arguments and computes final -+ * string length, second pass copies strings into a buffer -+ * allocated directly with the correct size. If the backend -+ * function plays nice, it won't coerce the buffer to a string -+ * (and thus intern it). -+ */ -+ -+ entry_lev = duk_get_current_magic(ctx); -+ if (entry_lev < DUK_LOG_TRACE || entry_lev > DUK_LOG_FATAL) { -+ /* Should never happen, check just in case. */ -+ return 0; -+ } -+ nargs = duk_get_top(ctx); -+ -+ /* [ arg1 ... argN this ] */ -+ -+ /* -+ * Log level check -+ */ -+ -+ duk_push_this(ctx); -+ -+ duk_get_prop_string(ctx, -1, "l"); -+ logger_lev = (duk_small_int_t) duk_get_int(ctx, -1); -+ if (entry_lev < logger_lev) { -+ return 0; -+ } -+ /* log level could be popped but that's not necessary */ -+ -+ now = duk_get_now(ctx); -+ duk_time_to_components(ctx, now, &comp); -+ sprintf((char *) date_buf, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", -+ (int) comp.year, (int) comp.month + 1, (int) comp.day, -+ (int) comp.hours, (int) comp.minutes, (int) comp.seconds, -+ (int) comp.milliseconds); -+ -+ date_len = strlen((const char *) date_buf); -+ -+ duk_get_prop_string(ctx, -2, "n"); -+ duk_to_string(ctx, -1); -+ -+ /* [ arg1 ... argN this loggerLevel loggerName ] */ -+ -+ /* -+ * Pass 1 -+ */ -+ -+ /* Line format: